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

TraceParserGen: Fix task guids and RegisterTemplate. #1414

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
86 changes: 54 additions & 32 deletions src/TraceParserGen/ETWManifest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,12 @@ public static List<Provider> ParseManifest(XmlReader reader, string fileName = n
}
}

if (provider.m_taskNames != null)
if (provider.m_tasks != null)
{
foreach (var taskId in new List<int>(provider.m_taskNames.Keys))
foreach (var keyValuePair in provider.m_tasks)
{
var taskName = provider.m_taskNames[taskId];
if (Provider.Replace(ref taskName, stringMap))
{
provider.m_taskNames[taskId] = taskName;
}
Task task = keyValuePair.Value;
Provider.Replace(ref task.LocalizedMessageOrName, stringMap);
}
}

Expand Down Expand Up @@ -176,15 +173,16 @@ public string GetKeywordSetString(ulong keywords, string separator = ",")
/* These are relatively rare APIs, normally you only care in the context of an event */
public string GetTaskName(ushort taskId)
{
if (m_taskNames == null)
if (m_tasks == null)
{
return "";
}

string ret;
if (m_taskNames.TryGetValue(taskId, out ret))
foreach(var kv in m_tasks)
{
return ret;
Task task = kv.Value;
if (task.Value == taskId)
return task.Name;
}

if (taskId == 0)
Expand Down Expand Up @@ -213,6 +211,20 @@ public string GetOpcodeName(ushort taskId, byte opcodeId)
return "Opcode" + opcodeId;
}

public string GetGuidName(string taskName)
{
string empty = "Guid.Empty";

if(string.IsNullOrEmpty(taskName))
return empty;

Task task = m_tasks[taskName];
if (task != null && task.EventGuid != Guid.Empty)
return $"{taskName}TaskGuid";
else
return empty;
}

/// <summary>
/// For debugging
/// </summary>
Expand Down Expand Up @@ -273,25 +285,15 @@ internal Provider(XmlReader reader, string fileName)
break;
case "task":
{
if (m_taskNames == null)
if (m_tasks == null)
{
m_taskNames = new Dictionary<int, string>();
m_taskValues = new Dictionary<string, int>();
m_tasks = new Dictionary<string, Task>();
}
string name = reader.GetAttribute("name");
int value = (int)ParseNumber(reader.GetAttribute("value"));
Task task = new Task(reader, this, lineInfo.LineNumber);
m_tasks.Add(task.Name, task);

string message = reader.GetAttribute("message");
if (message == null)
{
message = name;
}

m_taskNames.Add(value, message);
m_taskValues.Add(name, value);

// Remember enuough to resolve opcodes nested inside this task.
curTask = value;
// Remember enough to resolve opcodes nested inside this task.
curTask = task.Value;
curTaskDepth = reader.Depth;
reader.Read();
}
Expand Down Expand Up @@ -358,7 +360,6 @@ internal Provider(XmlReader reader, string fileName)
}

// We are done with these. Free up some space.
m_taskValues = null;
m_opcodeValues = null;
m_keywordValues = null;
m_templateValues = null;
Expand Down Expand Up @@ -555,12 +556,10 @@ private void ReadTemplate(XmlReader reader)

private List<Event> m_events = new List<Event>();
internal string[] m_keywordNames;
internal Dictionary<int, string> m_taskNames;
internal Dictionary<string, Task> m_tasks;
// Note that the key is task << 8 + opcode to allow for private opcode names
internal Dictionary<int, string> m_opcodeNames;

// These are not used after parsing.
internal Dictionary<string, int> m_taskValues;
// Note that the value is task << 8 + opcode to allow for private opcode names
// Also the key is taskId : opcodeName again to allow private opcode names or simply opcodeName if it is global.
internal Dictionary<string, int> m_opcodeValues;
Expand Down Expand Up @@ -747,7 +746,7 @@ internal void ResolveIdsInEvent(string fileName = null)
m_taskId = null;
if (id != null)
{
Task = (ushort)m_provider.m_taskValues[id];
Task = (ushort)m_provider.m_tasks[id].Value;
}

id = m_opcodeId;
Expand Down Expand Up @@ -833,6 +832,29 @@ internal void UpdateStrings(Dictionary<string, string> stringMap)
#endregion
}

/// <summary>
/// A task represents the Task Element in the manifest.
/// </summary>
public sealed class Task
{
public int Value { get; internal set; }
public string Name { get; internal set; }
public string Message { get; internal set; }
public string LocalizedMessageOrName;
public Guid EventGuid { get; internal set; }

internal Task(XmlReader reader, Provider provider, int lineNum)
{
Name = reader.GetAttribute("name");
Value = (int)Provider.ParseNumber(reader.GetAttribute("value"));

Message = reader.GetAttribute("message");
LocalizedMessageOrName = Message ?? Name;

string guid = reader.GetAttribute("eventGUID");
EventGuid = (guid != null) ? Guid.Parse(guid) : Guid.Empty;
}
}
/// <summary>
/// A field represents one field in a ETW event
/// </summary>
Expand Down
36 changes: 27 additions & 9 deletions src/TraceParserGen/TraceParserGen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ private void GenerateTraceEventParserClass(TextWriter output)
output.WriteLine(" public sealed class " + ClassNamePrefix + "TraceEventParser : TraceEventParser ");
output.WriteLine(" {");
output.WriteLine(" public static string ProviderName = \"" + m_provider.Name + "\";");
output.WriteLine(" public static Guid ProviderGuid = " + CodeForGuidLiteral(m_provider.Id) + ";");
GenerateGuids(output);
GenerateKeywords(output);
output.WriteLine(" public " + ClassNamePrefix + "TraceEventParser(TraceEventSource source) : base(source) {}");
output.WriteLine("");
Expand Down Expand Up @@ -190,6 +190,21 @@ private void GenerateTraceEventParserClass(TextWriter output)
output.WriteLine("}");
}

private void GenerateGuids(TextWriter output)
{
output.WriteLine(" public static Guid ProviderGuid = " + CodeForGuidLiteral(m_provider.Id) + ";");
foreach (var kv in m_provider.m_tasks)
{
string taskName = kv.Key;
Task task = kv.Value;
if(task.EventGuid != Guid.Empty)
{
string guidName = m_provider.GetGuidName(taskName);
output.WriteLine(" public static Guid {0} = {1};", guidName, CodeForGuidLiteral(task.EventGuid));
}
}
}

private void GenerateKeywords(TextWriter output)
{
output.WriteLine(" public enum Keywords : long");
Expand Down Expand Up @@ -297,14 +312,13 @@ private void GenerateTemplateDefs(TextWriter output)
for (int i = 0; i < m_provider.Events.Count; i++)
{
var evnt = m_provider.Events[i];
string guid = m_provider.GetGuidName(evnt.TaskName);

// check if the same event template has not been already defined (different versions of the same event)
output.WriteLine(" templates[{0}] = new {1}TraceData(null, {2}, {3}, \"{4}\", {4}TaskGuid, {5}, \"{6}\", ProviderGuid, ProviderName);",
i, TraceParserGen.ToCSharpName(evnt.EventName),
evnt.Id, evnt.Task, TraceParserGen.ToCSharpName(evnt.TaskName), evnt.Opcode, TraceParserGen.ToCSharpName(evnt.OpcodeName)
output.WriteLine(" templates[{0}] = new {1}(null, {2}, {3}, \"{4}\", {5}, {6}, \"{7}\", ProviderGuid, ProviderName);",
i, GetTemplateNameForEvent(evnt, evnt.EventName),
evnt.Id, evnt.Task, TraceParserGen.ToCSharpName(evnt.TaskName), guid, evnt.Opcode, TraceParserGen.ToCSharpName(evnt.OpcodeName)
);
// as of today, the generated code won't compile because the task GUID is not defined
// TODO: define the xxxTaskGuid based on eventGUID attribute of <task> elements of the .man file
}

output.WriteLine(" s_templates = templates;");
Expand All @@ -314,6 +328,12 @@ private void GenerateTemplateDefs(TextWriter output)
output.WriteLine(" callback(template);");
output.WriteLine(" }");
output.WriteLine();

output.WriteLine(" private void RegisterTemplate(TraceEvent template)");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this is a compromise between the previous style and the current style. Personally, I like the current style, which omits this private method call but it isn't any different in practice

output.WriteLine(" {");
output.WriteLine(" Debug.Assert(template.ProviderGuid == " + ClassNamePrefix + "TraceEventParser.ProviderGuid);");
output.WriteLine(" source.RegisterEventTemplate(template);");
output.WriteLine(" }");
}

/// <summary>
Expand All @@ -340,9 +360,7 @@ private void GenerateEvents(TextWriter output)
output.WriteLine(" {");
output.WriteLine(" add");
output.WriteLine(" {");
var taskGuid = (string.IsNullOrEmpty(evnt.TaskName))
? "Guid.Empty"
: evnt.TaskName + "TaskGuid";
var taskGuid = m_provider.GetGuidName(evnt.TaskName);
var taskName = TraceParserGen.ToCSharpName(evnt.TaskName);
if (string.IsNullOrEmpty(taskName)) taskName = evntName;
// Call the *Template() function that does the work
Expand Down