Skip to content

Commit

Permalink
Add --collect-spmi-to to collect SPMI collections
Browse files Browse the repository at this point in the history
When used, it should point to an existing directory in which SPMI
collections of all of the host invocations will be created. It requires
the SPMI shim to exist next to the host.
  • Loading branch information
jakobbotsch committed Jan 18, 2024
1 parent c10b52e commit 3aecec6
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 7 deletions.
8 changes: 5 additions & 3 deletions Fuzzlyn/ExecutionServerPool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ internal class ExecutionServerPool
// Stop a server once it has not been used for this duration
private static readonly TimeSpan s_inactivityPeriod = TimeSpan.FromMinutes(3);

public ExecutionServerPool(string host)
public ExecutionServerPool(string host, SpmiSetupOptions spmiOptions)
{
Host = host;
SpmiOptions = spmiOptions;
}

public string Host { get; }
public SpmiSetupOptions SpmiOptions { get; }

private List<RunningExecutionServer> _pool = new();

Expand Down Expand Up @@ -46,7 +48,7 @@ private RunningExecutionServer Get(bool keepNonEmptyEagerly)

if (startNew)
{
RunningExecutionServer created = RunningExecutionServer.Create(Host);
RunningExecutionServer created = RunningExecutionServer.Create(Host, SpmiOptions);
lock (_pool)
{
_pool.Add(created);
Expand All @@ -56,7 +58,7 @@ private RunningExecutionServer Get(bool keepNonEmptyEagerly)
if (bestServer != null)
return bestServer;

return RunningExecutionServer.Create(Host);
return RunningExecutionServer.Create(Host, SpmiOptions);
}

private void Return(RunningExecutionServer server)
Expand Down
1 change: 1 addition & 0 deletions Fuzzlyn/FuzzlynOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ internal class FuzzlynOptions
public bool Output { get; set; } = false;
public bool EnableChecksumming { get; set; } = true;
public bool Reduce { get; set; } = false;
public string CollectSpmiTo { get; set; }
public bool Execute { get; set; } = true;
public bool Stats { get; set; } = false;
public KnownErrors KnownErrors { get; set; }
Expand Down
7 changes: 7 additions & 0 deletions Fuzzlyn/Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,11 @@ public static void SetExecutionEnvironmentVariables(StringDictionary envVars)
envVars["DOTNET_TieredCompilation"] = "0";
envVars["DOTNET_JitThrowOnAssertionFailure"] = "1";
}

public static void SetSpmiCollectionEnvironmentVariables(StringDictionary envVars, SpmiSetupOptions options)
{
envVars["DOTNET_JitName"] = options.ShimName;
envVars["SuperPMIShimLogPath"] = options.CollectionDirectory;
envVars["SuperPMIShimPath"] = options.JitPath;
}
}
18 changes: 16 additions & 2 deletions Fuzzlyn/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ private static void Main(string[] args)
bool? enableChecksumming = null;
bool? reduce = null;
string reduceDebugGitDir = null;
string collectSpmiTo = null;
string outputPath = null;
bool? stats = null;
bool? execute = null;
Expand All @@ -60,6 +61,7 @@ private static void Main(string[] args)
{ "reduce", "Reduce program to a minimal example", v => reduce = v != null },
{ "output=", "Output program source to this path. Also enables writing updates in the console during reduction.", v => outputPath = v },
{ "reduce-debug-git-dir=", "Create reduce path in specified dir (must not exists beforehand)", v => reduceDebugGitDir = v },
{ "collect-spmi-to=", "Collect SPMI collections to specified directory", v => collectSpmiTo = v },
{ "stats", "Generate a bunch of programs and record their sizes", v => stats = v != null },
{ "execute", "Whether or not to execute the generated and compiled programs (enabled by default, disable with --execute-) ", v => execute = v != null },
{ "known-errors=", "A JSON file of known error strings that will be ignored, or the string \"dotnet/runtime\" to use a built-in list for the tip of dotnet/runtime.", v => knownErrors = v },
Expand Down Expand Up @@ -117,6 +119,8 @@ private static void Main(string[] args)
options.EnableChecksumming = enableChecksumming.Value;
if (reduce.HasValue)
options.Reduce = reduce.Value;
if (collectSpmiTo != null)
options.CollectSpmiTo = collectSpmiTo;
if (stats.HasValue)
options.Stats = stats.Value;
if (execute.HasValue)
Expand Down Expand Up @@ -176,11 +180,21 @@ private static bool CreateExecutionServerPool(FuzzlynOptions options)
{
if (!File.Exists(options.Host))
{
Console.WriteLine("Error: invalid host specified");
Console.WriteLine("Error: invalid host specified ({0})", options.Host);
return false;
}

s_executionServerPool = new ExecutionServerPool(options.Host);
SpmiSetupOptions spmiOptions = null;
if (options.CollectSpmiTo != null)
{
spmiOptions = SpmiSetupOptions.Create(options.CollectSpmiTo, options.Host, out string error);
if (spmiOptions == null)
{
Console.WriteLine("Error: {0}", error);
return false;
}
}
s_executionServerPool = new ExecutionServerPool(options.Host, spmiOptions);
return true;
}

Expand Down
20 changes: 19 additions & 1 deletion Fuzzlyn/Reduction/Reducer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -651,10 +651,16 @@ private bool IsStandaloneProgramInteresting(CompilationUnitSyntax prog)
(string debugStdout, string debugStderr) = ExecuteInSubProcess(prog, Compiler.DebugOptions.WithOutputKind(OutputKind.ConsoleApplication), tempAsmPath);
(string releaseStdout, string releaseStderr) = ExecuteInSubProcess(prog, Compiler.ReleaseOptions.WithOutputKind(OutputKind.ConsoleApplication), tempAsmPath);
if (debugStderr.Contains("Assert failure") || debugStderr.Contains("JIT assert failed"))
{
Console.WriteLine("Standalone is interesting due to assert failure in debug:{0}{1}", Environment.NewLine, debugStderr);
return true;
}

if (releaseStderr.Contains("Assert failure") || releaseStderr.Contains("JIT assert failed"))
{
Console.WriteLine("Standalone is interesting due to assert failure in release:{0}{1}", Environment.NewLine, releaseStderr);
return true;
}

string[] debugStderrLines = debugStderr.ReplaceLineEndings().Split(Environment.NewLine);
string[] releaseStderrLines = releaseStderr.ReplaceLineEndings().Split(Environment.NewLine);
Expand All @@ -663,9 +669,18 @@ private bool IsStandaloneProgramInteresting(CompilationUnitSyntax prog)
string debugExceptionLine = debugStderrLines.FirstOrDefault(l => l.Contains("Unhandled exception."));
string releaseExceptionLine = releaseStderrLines.FirstOrDefault(l => l.Contains("Unhandled exception."));
if (debugExceptionLine != releaseExceptionLine)
{
Console.WriteLine("Standalone is interesting due to different unhandled exceptions:{0}{1}{0}VS{0}{2}", Environment.NewLine, debugExceptionLine, releaseExceptionLine);
return true;
}

if (debugStdout != releaseStdout)
{
Console.WriteLine("Standalone is interesting due to different stdout:{0}{1}{0}VS{0}{2}", Environment.NewLine, debugStdout, releaseStdout);
return true;
}

return debugStdout != releaseStdout;
return false;
}
finally
{
Expand Down Expand Up @@ -705,6 +720,9 @@ private bool IsStandaloneProgramInteresting(CompilationUnitSyntax prog)

Helpers.SetExecutionEnvironmentVariables(info.EnvironmentVariables);

if (_pool.SpmiOptions != null)
Helpers.SetSpmiCollectionEnvironmentVariables(info.EnvironmentVariables, _pool.SpmiOptions);

// WER mode is inherited by child, so if this is a crash we can
// make sure no WER dialog opens by disabling it for our own
// process.
Expand Down
8 changes: 7 additions & 1 deletion Fuzzlyn/RunningExecutionServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ public void Kill()
}
}

public static RunningExecutionServer Create(string host)
public static RunningExecutionServer Create(string host, SpmiSetupOptions spmiOptions)
{
string executorPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Fuzzlyn.ExecutionServer.dll");
ProcessStartInfo info = new()
Expand All @@ -140,6 +140,12 @@ public static RunningExecutionServer Create(string host)
info.ArgumentList.Add(executorPath);

Helpers.SetExecutionEnvironmentVariables(info.EnvironmentVariables);

if (spmiOptions != null)
{
Helpers.SetSpmiCollectionEnvironmentVariables(info.EnvironmentVariables, spmiOptions);
}

Process proc = Process.Start(info);
return new RunningExecutionServer(proc);
}
Expand Down
63 changes: 63 additions & 0 deletions Fuzzlyn/SpmiSetupOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Fuzzlyn;

internal class SpmiSetupOptions
{
public string CollectionDirectory { get; private set; }
public string ShimPath { get; private set; }
public string ShimName { get; private set; }
public string JitPath { get; private set; }

public static SpmiSetupOptions Create(string collectionDir, string host, out string error)
{
if (!Directory.Exists(collectionDir))
{
error = $"SPMI collection directory {collectionDir} does not exist";
return null;
}

SpmiSetupOptions options = new()
{
CollectionDirectory = collectionDir
};

string hostDir = Path.GetDirectoryName(host);
(string shimName, string jitName)[] setups =
{
("superpmi-shim-collector.dll", "clrjit.dll"),
("libsuperpmi-shim-collector.so", "libclrjit.so"),
("libsuperpmi-shim-collector.dylib", "libclrjit.dylib")
};

foreach ((string shimName, string jitName) in setups)
{
string shimPath = Path.Combine(hostDir, shimName);
if (!File.Exists(shimPath))
{
continue;
}

string jitPath = Path.Combine(hostDir, jitName);
if (!File.Exists(jitPath))
{
error = $"Expected JIT to exist next to SPMI shim (at {jitPath})";
return null;
}

options.ShimPath = shimPath;
options.ShimName = shimName;
options.JitPath = jitPath;
error = null;
return options;
}

error = $"Could not find an SPMI shim in host directory {hostDir}";
return null;
}
}

0 comments on commit 3aecec6

Please sign in to comment.