Skip to content
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

Implement command line preset import #1496

Open
wants to merge 1 commit 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
7 changes: 7 additions & 0 deletions src/PerfView/CommandLineArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ public static string GetHelpString(int maxLineWidth)
public string CGL_PathToOutputFile;
#endif

// import presets options
public string PresetsFile;

// view options
public string Process; // A process name to focus on.

Expand Down Expand Up @@ -642,6 +645,10 @@ private void SetupCommandLine(CommandLineParser parser)
parser.DefineParameterSet("GuiHeapSnapshot", ref DoCommand, App.CommandProcessor.GuiHeapSnapshot,
"Opens the 'TakeHeapSnapshot' dialog box.");

parser.DefineParameterSet("ImportPresets", ref DoCommand, App.CommandProcessor.ImportPresets,
"Imports presets from the file.");
parser.DefineParameter("PresetFile", ref PresetsFile, "The path of the file to import presets from.");

parser.DefineParameterSet("UserCommand", ref DoCommand, App.CommandProcessor.UserCommand,
"Runs a user defined command. Type 'PerfView UserCommandHelp' to see the help for all the user commands. " +
"See PerfView Extensions in the users guide for more on creating user commands.");
Expand Down
8 changes: 8 additions & 0 deletions src/PerfView/CommandProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2070,6 +2070,14 @@ public void CollectCrossGenerationLiveness(CommandLineArgs parsedArgs)

}
#endif
public void ImportPresets(CommandLineArgs parsedArgs)
{
LogFile.WriteLine("Importing presets from '{0}'", parsedArgs.PresetsFile);
var presets = Preset.LoadPresets();
Preset.Import(parsedArgs.PresetsFile, presets, p => LogFile.WriteLine("Imported preset '{0}'", p.Name), LogFile);
Preset.SavePresets(presets);
LogFile.WriteLine("Importing presets completed.");
}

#region private
private void DisableNetMonTrace()
Expand Down
70 changes: 3 additions & 67 deletions src/PerfView/Dialogs/ManagePresetsDialog.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,18 +113,7 @@ private void ExportPresets(object sender, RoutedEventArgs e)
return;
}
string fileName = saveDialog.FileName;

using (XmlWriter writer = XmlWriter.Create(
fileName,
new XmlWriterSettings() { Indent = true, NewLineOnAttributes = true }))
{
writer.WriteStartElement("Presets");
foreach (Preset preset in Presets)
{
writer.WriteElementString("Preset", Preset.Serialize(preset));
}
writer.WriteEndElement();
}
Preset.Export(Presets, fileName);
m_log.LogWriter.WriteLine($"[Presets exported to {fileName}.]");
}
private void ImportPresets(object sender, RoutedEventArgs e)
Expand All @@ -146,62 +135,9 @@ private void ImportPresets(object sender, RoutedEventArgs e)

string fileName = openDialog.FileName;

List<Preset> presetsFromFile = new List<Preset>();
XmlReaderSettings settings = new XmlReaderSettings() { IgnoreWhitespace = true, IgnoreComments = true };
using (XmlReader reader = XmlTextReader.Create(fileName, settings))
{
int entryDepth = reader.Depth;
try
{
reader.Read();
while (true)
{
if (reader.NodeType == XmlNodeType.Element && reader.Depth > entryDepth)
{
string value = reader.ReadElementContentAsString();
presetsFromFile.Add(Preset.ParsePreset(value));
continue;
}

if (!reader.Read())
{
break;
}
}
}
catch (Exception ex)
{
m_log.LogWriter.WriteLine($"[Import of presets from {fileName} has failed.]");
m_log.LogWriter.WriteLine("Error during reading presets file: " + ex);
}
}

// Now we have current presets in Presets collection and new presets in presetsFromFile collection.
// Existing identical presets are ignored.
// Existing presets that differ are ignored too, but warning is written into logs.
int imported = 0, ignored = 0;
foreach (var preset in presetsFromFile)
{
var existingPreset = Presets.FirstOrDefault(x => x.Name == preset.Name);
if (existingPreset == null)
{
Presets.Add(preset);
PresetListBox.Items.Add(preset.Name);
imported++;
continue;
}

if (existingPreset.Equals(preset))
{
imported++;
continue;
}

m_log.LogWriter.WriteLine($"WARN: Preset '{preset.Name}' was ignored during import because there already exist a preset with the same name.");
ignored++;
}
m_log.LogWriter.WriteLine($"[Import of presets completed: {imported} imported, {ignored} ignored.]");
Preset.Import(fileName, Presets, p => PresetListBox.Items.Add(p.Name), m_log.LogWriter);
}

private void DoPresetSelected(object sender, SelectionChangedEventArgs e)
{
var selectedItem = PresetListBox.SelectedItem;
Expand Down
153 changes: 117 additions & 36 deletions src/PerfView/StackViewer/Preset.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;

Expand Down Expand Up @@ -42,8 +44,10 @@ public bool Equals(Preset other)
/// <summary>
/// Parses collection of presets kept as a string
/// </summary>
public static List<Preset> ParseCollection(string presets)
public static List<Preset> LoadPresets()
{
string presets = App.ConfigData["Presets"];

if (presets == null)
{
return new List<Preset>(0);
Expand All @@ -59,9 +63,119 @@ public static List<Preset> ParseCollection(string presets)
}

/// <summary>
/// Parses single preset.
/// Saves all presets into the configuration file.
/// </summary>
public static void SavePresets(List<Preset> presets)
{
var result = new StringBuilder();
bool firstPreset = true;
foreach (var preset in presets)
{
if (!firstPreset)
{
result.Append(PresetSeparator);
}
firstPreset = false;

result.Append(Serialize(preset));
}

App.ConfigData["Presets"] = result.ToString();
}

/// <summary>
/// Exports presets to a given file.
/// </summary>
public static Preset ParsePreset(string presetString)
public static void Export(List<Preset> presets, string fileName)
{
using (XmlWriter writer = XmlWriter.Create(
fileName,
new XmlWriterSettings() { Indent = true, NewLineOnAttributes = true }))
{
writer.WriteStartElement("Presets");
foreach (Preset preset in presets)
{
writer.WriteElementString("Preset", Preset.Serialize(preset));
}
writer.WriteEndElement();
}
}

/// <summary>
/// Imports presets from a file to a given collection.
/// </summary>
public static void Import(string fileName, List<Preset> target, Action<Preset> importAction, TextWriter logWriter)
{
List<Preset> presetsFromFile = new List<Preset>();
XmlReaderSettings settings = new XmlReaderSettings() { IgnoreWhitespace = true, IgnoreComments = true };
using (XmlReader reader = XmlTextReader.Create(fileName, settings))
{
int entryDepth = reader.Depth;
try
{
reader.Read();
while (true)
{
if (reader.NodeType == XmlNodeType.Element && reader.Depth > entryDepth)
{
string value = reader.ReadElementContentAsString();
presetsFromFile.Add(Preset.ParsePreset(value));
continue;
}

if (!reader.Read())
{
break;
}
}
}
catch (Exception ex)
{
logWriter.WriteLine($"[Import of presets from {fileName} has failed.]");
logWriter.WriteLine("Error during reading presets file: " + ex);
}
}

// Now we have current presets in 'target' collection and new presets in presetsFromFile collection.
// Existing identical presets are ignored.
// Existing presets that differ are ignored too, but warning is written into logs.
// For imported presets an action is called
int imported = 0, existing = 0, ignored = 0;
foreach (var preset in presetsFromFile)
{
var existingPreset = target.FirstOrDefault(x => x.Name == preset.Name);
if (existingPreset == null)
{
target.Add(preset);
importAction?.Invoke(preset);
imported++;
continue;
}

if (existingPreset.Equals(preset))
{
existing++;
continue;
}

logWriter.WriteLine($"WARN: Preset '{preset.Name}' was ignored during import because there already exist a different preset with the same name.");
ignored++;
}
logWriter.WriteLine($"[Import of presets completed: {imported} imported, {existing} existed, {ignored} ignored.]");
}

private static string Serialize(Preset preset)
{
var result = new StringBuilder();
result.Append("Name=" + preset.Name + PartSeparator);
result.Append("GroupPat=" + preset.GroupPat + PartSeparator);
result.Append("FoldPercentage=" + preset.FoldPercentage + PartSeparator);
result.Append("FoldPat=" + preset.FoldPat + PartSeparator);
result.Append("Comment=" + XmlConvert.EncodeName(preset.Comment));
return result.ToString();
}

private static Preset ParsePreset(string presetString)
{
var preset = new Preset();
var presetParts = presetString.Split(new[] { PartSeparator }, StringSplitOptions.None);
Expand Down Expand Up @@ -93,40 +207,7 @@ public static Preset ParsePreset(string presetString)
return preset;
}

/// <summary>
/// Serializes list of presets to be stored in the string.
/// </summary>
public static string Serialize(List<Preset> presets)
{
var result = new StringBuilder();
bool firstPreset = true;
foreach (var preset in presets)
{
if (!firstPreset)
{
result.Append(PresetSeparator);
}
firstPreset = false;

result.Append(Serialize(preset));
}

return result.ToString();
}

/// <summary>
/// Serializes single preset to string.
/// </summary>
public static string Serialize(Preset preset)
{
var result = new StringBuilder();
result.Append("Name=" + preset.Name + PartSeparator);
result.Append("GroupPat=" + preset.GroupPat + PartSeparator);
result.Append("FoldPercentage=" + preset.FoldPercentage + PartSeparator);
result.Append("FoldPat=" + preset.FoldPat + PartSeparator);
result.Append("Comment=" + XmlConvert.EncodeName(preset.Comment));
return result.ToString();
}

private const string PresetSeparator = "####";
private const string PartSeparator = "$$$$";
Expand Down
7 changes: 3 additions & 4 deletions src/PerfView/StackViewer/StackWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3896,8 +3896,7 @@ private static void UpdateDiffMenu(string diffName, MenuItem diffMenuItem, Actio

private void ConfigurePresetMenu()
{
var presets = App.ConfigData["Presets"];
m_presets = Preset.ParseCollection(presets);
m_presets = Preset.LoadPresets();

foreach (var preset in m_presets)
{
Expand Down Expand Up @@ -3985,7 +3984,7 @@ private void DoSaveAsPreset(object sender, RoutedEventArgs e)
m_presets.Insert(0, preset);
m_presets.Sort((x, y) => Comparer<string>.Default.Compare(x.Name, y.Name));
}
App.ConfigData["Presets"] = Preset.Serialize(m_presets);
Preset.SavePresets(m_presets);

DoUpdatePresetMenu();
}
Expand All @@ -3996,7 +3995,7 @@ private void DoManagePresets(object sender, RoutedEventArgs e)
managePresetsDialog.Owner = this;
managePresetsDialog.ShowDialog();
m_presets = managePresetsDialog.Presets;
App.ConfigData["Presets"] = Preset.Serialize(m_presets);
Preset.SavePresets(m_presets);
DoUpdatePresetMenu();
}

Expand Down
Loading