Skip to content

common class for server run command build #4851

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using GC.Infrastructure.Core.Configurations.ASPNetBenchmarks;
using GC.Infrastructure.Core.TraceCollection;
using System.Linq;
using System.Text;

namespace GC.Infrastructure.Core.CommandBuilders
Expand All @@ -10,162 +11,84 @@ public static (string, string) Build(ASPNetBenchmarksConfiguration configuration
{
string processName = "crank";
StringBuilder commandStringBuilder = new();

// Load the base configuration.
commandStringBuilder.Append(benchmarkNameToCommand.Value);

List<KeyValuePair<string, string>> keyValueArgsList = new();

// Environment Variables.
// Add the environment variables from the configuration.
Dictionary<string, string> environmentVariables = new();
foreach (var env in configuration.Environment!.environment_variables)
{
environmentVariables[env.Key] = env.Value;
}
var environmentVariables = ServerRunCommandBuilder.OverrideDictionary(
configuration.Environment!.environment_variables!,
run.Value!.environment_variables!);

// Add overrides, if available.
if (run.Value.environment_variables != null)
{
foreach (var env in run.Value.environment_variables)
{
environmentVariables[env.Key] = env.Value;
}
}
keyValueArgsList.AddRange(
ServerRunCommandBuilder.GenerateKeyValuePairListForEnvironmentVariables(environmentVariables));

foreach (var env in environmentVariables)
// Check if the log file is specified, also add the fact that we want to retrieve the log file back.
// This log file should be named in concordance with the name of the run and the benchmark.
string? fileNameOfLog = environmentVariables!.GetValueOrDefault("DOTNET_GCLogFile", null);
if (!String.IsNullOrEmpty(fileNameOfLog))
{
string variable = env.Value;

// Check if the log file is specified, also add the fact that we want to retrieve the log file back.
// This log file should be named in concordance with the name of the run and the benchmark.
if (string.CompareOrdinal(env.Key, "DOTNET_GCLogFile") == 0)
{
string fileNameOfLog = Path.GetFileName(env.Value);
commandStringBuilder.Append($" --application.options.downloadFiles \"*{fileNameOfLog}.log\" ");
commandStringBuilder.Append($" --application.options.downloadFilesOutput \"{Path.Combine(configuration.Output!.Path, run.Key, $"{benchmarkNameToCommand.Key}_GCLog")}\" ");
}

commandStringBuilder.Append($" --application.environmentVariables {env.Key}={variable} ");
string gcLogDownloadPath = Path.Combine(configuration.Output!.Path, run.Key, $"{benchmarkNameToCommand.Key}_GCLog");
keyValueArgsList.AddRange(
ServerRunCommandBuilder.GenerateKeyValuePairListForGCLog(fileNameOfLog, gcLogDownloadPath));
}

// Trace Collection.
// If the TraceConfiguration Key is specified in the yaml and
if (configuration.TraceConfigurations != null && !string.Equals(configuration.TraceConfigurations.Type, "none", StringComparison.OrdinalIgnoreCase))
{
CollectType collectType = TraceCollector.StringToCollectTypeMap[configuration.TraceConfigurations.Type];
string collectionCommand = TraceCollector.WindowsCollectTypeMap[collectType];
collectionCommand = collectionCommand.Replace(" ", ";").Replace("/", "");

string traceFileSuffix = ".etl.zip";
// Add specific commands.
if (os == OS.Windows)
{
commandStringBuilder.Append(" --application.collect true ");
commandStringBuilder.Append(" --application.collectStartup true ");
commandStringBuilder.Append($" --application.collectArguments \"{collectionCommand}\" ");
}

else
{
if (configuration.TraceConfigurations.Type != "gc")
{
throw new ArgumentException($"{nameof(ASPNetBenchmarksCommandBuilder)}: Currently only GCCollectOnly traces are allowed for Linux.");
}

else
{
traceFileSuffix = ".nettrace";
commandStringBuilder.Append(" --application.dotnetTrace true ");
commandStringBuilder.Append(" --application.dotnetTraceProviders gc-collect ");
}
}

// Add name of output.
commandStringBuilder.Append($" --application.options.traceOutput {Path.Combine(configuration.Output.Path, run.Key, (benchmarkNameToCommand.Key + "." + collectType)) + traceFileSuffix}");
}
string traceFileSuffix = os == OS.Windows? ".etl.zip": ".nettrace";
string tracePath = Path.Combine(configuration.Output.Path, run.Key, (benchmarkNameToCommand.Key + "." + collectType)) + traceFileSuffix;

string frameworkVersion = configuration.Environment.framework_version;
// Override the framework version if it's specified at the level of the run.
if (!string.IsNullOrEmpty(run.Value.framework_version))
{
frameworkVersion = run.Value.framework_version;
keyValueArgsList.AddRange(
ServerRunCommandBuilder.GenerateKeyValuePairListForTrace(configuration.TraceConfigurations.Type, tracePath, os));
}
commandStringBuilder.Append($" --application.framework {frameworkVersion} ");

string artifactsToUpload = run.Value.corerun!;
// Override the framework version if it's specified at the level of the run.
string frameworkVersion = string.IsNullOrEmpty(run.Value.framework_version) ?
configuration.Environment.framework_version : run.Value.framework_version;
keyValueArgsList.AddRange(
ServerRunCommandBuilder.GenerateKeyValuePairListForFramework(frameworkVersion));

// If the corerun specified is a directory, upload the entire directory.
// Else, we upload just the file.
if (Directory.Exists(run.Value.corerun!))
{
artifactsToUpload = Path.Combine(artifactsToUpload, "*.*");
}
commandStringBuilder.Append($" --application.options.outputFiles {artifactsToUpload} ");
keyValueArgsList.AddRange(
ServerRunCommandBuilder.GenerateKeyValuePairListForUploadFiles(run.Value.corerun));

// Get the logs.
commandStringBuilder.Append(" --application.options.downloadOutput true ");
commandStringBuilder.Append($" --application.options.downloadOutputOutput {Path.Combine(configuration.Output.Path, run.Key, $"{benchmarkNameToCommand.Key}_{run.Key}.output.log")} ");

commandStringBuilder.Append(" --application.options.downloadBuildLog true ");
commandStringBuilder.Append($" --application.options.downloadBuildLogOutput {Path.Combine(configuration.Output.Path, run.Key, $"{benchmarkNameToCommand.Key}_{run.Key}.build.log")} ");

commandStringBuilder.Append($" --json {Path.Combine(configuration.Output.Path, run.Key, $"{benchmarkNameToCommand.Key}_{run.Key}.json")}");
string logDownloadPathWithoutExtension = Path.Combine(
configuration.Output.Path, run.Key, $"{benchmarkNameToCommand.Key}_{run.Key}");
keyValueArgsList.AddRange(
ServerRunCommandBuilder.GenerateKeyValuePairListForGettingLogs(logDownloadPathWithoutExtension));

// Add the extra metrics by including the configuration.
commandStringBuilder.Append($" --config {Path.Combine("Commands", "RunCommand", "BaseSuite", "PercentileBasedMetricsConfiguration.yml")} ");

// Add any additional arguments specified.
if (!string.IsNullOrEmpty(configuration.benchmark_settings.additional_arguments))
{
commandStringBuilder.Append($" {configuration.benchmark_settings.additional_arguments} ");
}

string commandString = commandStringBuilder.ToString();
string configPath = Path.Combine("Commands", "RunCommand", "BaseSuite", "PercentileBasedMetricsConfiguration.yml");
keyValueArgsList.AddRange(
ServerRunCommandBuilder.GenerateKeyValuePairListForConfig(configPath));

// Apply overrides.
if (!string.IsNullOrEmpty(configuration.benchmark_settings.override_arguments))
{
List<KeyValuePair<string, string>> overrideCommands = GetCrankArgsAsList(configuration.benchmark_settings.override_arguments);
if (overrideCommands.Count > 0)
{
// Take the current commands and first replace all the keys that match the override commands.
// Subsequently, add the new overrides and then convert the key-value pair list back to a string.
List<KeyValuePair<string, string>> currentCommands = GetCrankArgsAsList(commandString);
foreach (var item in overrideCommands)
{
var existing = currentCommands.Where(kv => kv.Key == item.Key).ToList();
foreach (var kv in existing)
{
if (kv.Key != null)
{
currentCommands.Remove(kv);
}
}

currentCommands.Add(item);
}

commandString = string.Join(" ", currentCommands.Select(c => $"--{c.Key} {c.Value}"));
}
}
List<KeyValuePair<string, string>> overrideCommands = ServerRunCommandBuilder.GetCrankArgsAsList(
configuration.benchmark_settings.override_arguments);

return (processName, commandString);
}
keyValueArgsList = ServerRunCommandBuilder.OverrideKeyValuePairList(
keyValueArgsList, overrideCommands);
}

internal static List<KeyValuePair<string, string>> GetCrankArgsAsList(string input)
{
var keyValuePairs = new List<KeyValuePair<string, string>>();
var splitStr = input.Split(new[] { "--" }, StringSplitOptions.RemoveEmptyEntries);
// Add key-Value arguments to commandStringBuilder
commandStringBuilder.Append(ServerRunCommandBuilder.ConvertKeyValueArgsListToString(keyValueArgsList));

foreach (var item in splitStr)
// Add any additional arguments specified.
if (!string.IsNullOrEmpty(configuration.benchmark_settings.additional_arguments))
{
var keyValue = item.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
if (keyValue.Length == 2)
{
keyValuePairs.Add(new KeyValuePair<string, string>(keyValue[0], keyValue[1]));
}
commandStringBuilder.Append($" {configuration.benchmark_settings.additional_arguments} ");
}

return keyValuePairs;
string commandString = commandStringBuilder.ToString();
return (processName, commandString);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,6 @@

namespace GC.Infrastructure.Core.CommandBuilders
{
public enum OS
{
Windows,
Linux
}

public static class GCPerfSimCommandBuilder
{
// Example output:
Expand Down Expand Up @@ -52,108 +46,57 @@ public static (string, string) BuildForServer(GCPerfSimConfiguration configurati
string processName = "crank";
StringBuilder commandStringBuilder = new();

List<KeyValuePair<string, string>> keyValueArgsList = new();

// Add the configuration and the scenario to be run.
string pathOfAssembly = Directory.GetParent(System.Reflection.Assembly.GetAssembly(typeof(GCPerfSimCommandBuilder)).Location).FullName;
commandStringBuilder.Append($"--config {Path.Combine(pathOfAssembly, "Commands", "RunCommand", "BaseSuite", "CrankConfiguration.yaml")} --scenario gcperfsim");
string configPath = Path.Combine(pathOfAssembly, "Commands", "RunCommand", "BaseSuite", "CrankConfiguration.yaml");

keyValueArgsList.AddRange(
ServerRunCommandBuilder.GenerateKeyValuePairListForConfig(configPath));
keyValueArgsList.AddRange(
ServerRunCommandBuilder.GenerateKeyValuePairListForScenario("gcperfsim"));

// Environment Variables.
// Add the environment variables from the configuration.
Dictionary<string, string> environmentVariables = new();
foreach (var env in configuration.Environment.environment_variables)
{
environmentVariables[env.Key] = env.Value;
}

// Add overrides, if available.
if (run.Value.environment_variables != null)
{
foreach (var env in run.Value.environment_variables)
{
environmentVariables[env.Key] = env.Value;
}
}

foreach (var env in environmentVariables)
{
commandStringBuilder.Append($" --application.environmentVariables {env.Key}={env.Value} ");
}
Dictionary<string, string> environmentVariables = ServerRunCommandBuilder.OverrideDictionary(
configuration.Environment.environment_variables, corerunOverride.Value.environment_variables);
environmentVariables = ServerRunCommandBuilder.OverrideDictionary(
environmentVariables, run.Value.environment_variables!);
keyValueArgsList.AddRange(
ServerRunCommandBuilder.GenerateKeyValuePairListForEnvironmentVariables(environmentVariables));

// GCPerfSim Configurations.
Dictionary<string, string> parameters = new();
foreach (var p in configuration.gcperfsim_configurations!.Parameters)
{
parameters[p.Key] = p.Value;
}

// Add overrides, if available.
if (run.Value?.override_parameters != null)
{
foreach (var p in run.Value.override_parameters)
{
parameters[p.Key] = p.Value;
}
}
Dictionary<string, string> parameters = ServerRunCommandBuilder.OverrideDictionary(
configuration.gcperfsim_configurations!.Parameters, run.Value.override_parameters);

foreach (var @params in parameters)
{
commandStringBuilder.Append($" --application.variables.{@params.Key} {@params.Value} ");
}
keyValueArgsList.AddRange(
ServerRunCommandBuilder.GenerateKeyValuePairListForParameters(parameters));

// Trace Collection.
// If the TraceConfiguration Key is specified in the yaml and
if (configuration.TraceConfigurations != null && !string.Equals(configuration.TraceConfigurations.Type, "none", StringComparison.OrdinalIgnoreCase))
{
CollectType collectType = TraceCollector.StringToCollectTypeMap[configuration.TraceConfigurations.Type];
string collectionCommand = os == OS.Windows ? TraceCollector.WindowsCollectTypeMap[collectType] : TraceCollector.LinuxCollectTypeMap[collectType];

collectionCommand = collectionCommand.Replace(" ", ";").Replace("/", "");

// Add specific commands.
if (os == OS.Windows)
{
commandStringBuilder.Append(" --application.collect true ");
commandStringBuilder.Append(" --application.collectStartup true ");
commandStringBuilder.Append($" --application.collectArguments {collectionCommand} ");
}

else
{
if (!string.Equals(configuration.TraceConfigurations.Type, "gc", StringComparison.OrdinalIgnoreCase))
{
throw new ArgumentException($"{nameof(GCPerfSimCommandBuilder)}: Currently only GCCollectOnly traces are allowed for Linux.");
}

commandStringBuilder.Append(" --application.dotnetTrace true ");
commandStringBuilder.Append(" --application.dotnetTraceProviders gc-collect ");
}
string extension = os == OS.Windows ? ".etl.zip" : ".nettrace";
string tracePath = Path.Combine(configuration.Output!.Path, run.Key, run.Key + "." + corerunOverride.Key + "." + iterationIdx + "." + collectType + extension);

commandStringBuilder.Append($" --application.framework net8.0 ");

// Add name of output.
string extension = os == OS.Windows ? "etl.zip" : "nettrace";
commandStringBuilder.Append($" --application.options.traceOutput {Path.Combine(configuration.Output!.Path, run.Key, run.Key + "." + corerunOverride.Key + "." + iterationIdx + "." + collectType + "." + extension)} ");
keyValueArgsList.AddRange(
ServerRunCommandBuilder.GenerateKeyValuePairListForTrace(configuration.TraceConfigurations.Type, tracePath, os));
keyValueArgsList.AddRange(
ServerRunCommandBuilder.GenerateKeyValuePairListForFramework("net8.0"));
}

if (corerunOverride.Value.environment_variables != null)
{
foreach (var env in corerunOverride.Value.environment_variables)
{
commandStringBuilder.Append($" --application.environmentVariables {env.Key}={env.Value} ");
}
}
// Upload corerun or Core_Root
keyValueArgsList.AddRange(
ServerRunCommandBuilder.GenerateKeyValuePairListForUploadFiles(corerunOverride.Value.Path));

// If Path is a file, upload single file.
if (File.Exists(corerunOverride.Value.Path))
{
commandStringBuilder.Append($" --application.options.outputFiles {corerunOverride.Value.Path}");
}
// If Path is a folder, upload entire folder.
if (Directory.Exists(corerunOverride.Value.Path))
{
commandStringBuilder.Append($" --application.options.outputFiles {Path.Combine(corerunOverride.Value.Path, "*")} ");
}
// Set profile
keyValueArgsList.AddRange(
ServerRunCommandBuilder.GenerateKeyValuePairListForProfile(serverName));

commandStringBuilder.Append($" --profile {serverName} ");
// Add key-Value arguments to commandStringBuilder
commandStringBuilder.Append(ServerRunCommandBuilder.ConvertKeyValueArgsListToString(keyValueArgsList));
return (processName, commandStringBuilder.ToString());
}
}
Expand Down
Loading