Skip to content

Commit

Permalink
Remove some allocations from ManifestBuilder.CreateManifestString (#4…
Browse files Browse the repository at this point in the history
…4532)

For the RuntimeEventSource, this removes around 30K of allocation, though that's only ~3% of what gets allocated.
  • Loading branch information
stephentoub authored Nov 18, 2020
1 parent 4e5463d commit e28dbe9
Showing 1 changed file with 97 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3278,10 +3278,15 @@ private static bool AttributeTypeNamesMatch(Type attributeType, Type reflectedAt
}
}
#endif
string eventKey = "event_" + eventName;
string? msg = manifest.GetLocalizedMessage(eventKey, CultureInfo.CurrentUICulture, etwFormat: false);
// overwrite inline message with the localized message
if (msg != null) eventAttribute.Message = msg;
if (manifest.HasResources)
{
string eventKey = "event_" + eventName;
if (manifest.GetLocalizedMessage(eventKey, CultureInfo.CurrentUICulture, etwFormat: false) is string msg)
{
// overwrite inline message with the localized message
eventAttribute.Message = msg;
}
}

AddEventDescriptor(ref eventData, eventName, eventAttribute, args, hasRelatedActivityID);
}
Expand Down Expand Up @@ -5366,23 +5371,34 @@ public void StartEvent(string eventName, EventAttribute eventAttribute)
numParams = 0;
byteArrArgIndices = null;

events.Append(" <event").
Append(" value=\"").Append(eventAttribute.EventId).Append('"').
Append(" version=\"").Append(eventAttribute.Version).Append('"').
Append(" level=\"").Append(GetLevelName(eventAttribute.Level)).Append('"').
Append(" symbol=\"").Append(eventName).Append('"');
events.Append(" <event value=\"").Append(eventAttribute.EventId).
Append("\" version=\"").Append(eventAttribute.Version).
Append("\" level=\"");
AppendLevelName(events, eventAttribute.Level);
events.Append("\" symbol=\"").Append(eventName).Append('"');

// at this point we add to the manifest's stringTab a message that is as-of-yet
// "untranslated to manifest convention", b/c we don't have the number or position
// of any byte[] args (which require string format index updates)
WriteMessageAttrib(events, "event", eventName, eventAttribute.Message);

if (eventAttribute.Keywords != 0)
events.Append(" keywords=\"").Append(GetKeywords((ulong)eventAttribute.Keywords, eventName)).Append('"');
{
events.Append(" keywords=\"");
AppendKeywords(events, (ulong)eventAttribute.Keywords, eventName);
events.Append('"');
}

if (eventAttribute.Opcode != 0)
{
events.Append(" opcode=\"").Append(GetOpcodeName(eventAttribute.Opcode, eventName)).Append('"');
}

if (eventAttribute.Task != 0)
{
events.Append(" task=\"").Append(GetTaskName(eventAttribute.Task, eventName)).Append('"');
}

#if FEATURE_MANAGED_ETW_CHANNELS
if (eventAttribute.Channel != 0)
{
Expand Down Expand Up @@ -5442,10 +5458,11 @@ public void EndEvent()

// at this point we have all the information we need to translate the C# Message
// to the manifest string we'll put in the stringTab
if (stringTab.TryGetValue("event_" + eventName, out string? msg))
string prefixedEventName = "event_" + eventName;
if (stringTab.TryGetValue(prefixedEventName, out string? msg))
{
msg = TranslateToManifestConvention(msg, eventName);
stringTab["event_" + eventName] = msg;
stringTab[prefixedEventName] = msg;
}

eventName = null;
Expand Down Expand Up @@ -5499,6 +5516,8 @@ public byte[] CreateManifest()

public IList<string> Errors => errors;

public bool HasResources => resources != null;

/// <summary>
/// When validating an event source it adds the error to the error collection.
/// When not validating it throws an exception if runtimeCritical is "true".
Expand All @@ -5516,6 +5535,10 @@ public void ManifestError(string msg, bool runtimeCritical = false)

private string CreateManifestString()
{
#if !ES_BUILD_STANDALONE
Span<char> ulongHexScratch = stackalloc char[16]; // long enough for ulong.MaxValue formatted as hex
#endif

#if FEATURE_MANAGED_ETW_CHANNELS
// Write out the channels
if (channelTab != null)
Expand All @@ -5530,7 +5553,6 @@ private string CreateManifestString()
ChannelInfo channelInfo = kvpair.Value;

string? channelType = null;
const string ElementName = "channel";
bool enabled = false;
string? fullName = null;
#if FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
Expand All @@ -5557,24 +5579,20 @@ private string CreateManifestString()

fullName ??= providerName + "/" + channelInfo.Name;

sb.Append(" <").Append(ElementName);
sb.Append(" chid=\"").Append(channelInfo.Name).Append('"');
sb.Append(" name=\"").Append(fullName).Append('"');
if (ElementName == "channel") // not applicable to importChannels.
{
Debug.Assert(channelInfo.Name != null);
WriteMessageAttrib(sb, "channel", channelInfo.Name, null);
sb.Append(" value=\"").Append(channel).Append('"');
if (channelType != null)
sb.Append(" type=\"").Append(channelType).Append('"');
sb.Append(" enabled=\"").Append(enabled ? "true" : "false").Append('"');
sb.Append(" <channel chid=\"").Append(channelInfo.Name).Append("\" name=\"").Append(fullName).Append('"');

Debug.Assert(channelInfo.Name != null);
WriteMessageAttrib(sb, "channel", channelInfo.Name, null);
sb.Append(" value=\"").Append(channel).Append('"');
if (channelType != null)
sb.Append(" type=\"").Append(channelType).Append('"');
sb.Append(" enabled=\"").Append(enabled ? "true" : "false").Append('"');
#if FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
if (access != null)
sb.Append(" access=\"").Append(access).Append("\"");
if (isolation != null)
sb.Append(" isolation=\"").Append(isolation).Append("\"");
if (access != null)
sb.Append(" access=\"").Append(access).Append("\"");
if (isolation != null)
sb.Append(" isolation=\"").Append(isolation).Append("\"");
#endif
}
sb.AppendLine("/>");
}
sb.AppendLine(" </channels>");
Expand Down Expand Up @@ -5625,7 +5643,14 @@ private string CreateManifestString()
// TODO: Warn people about the dropping of values.
if (isbitmap && ((hexValue & (hexValue - 1)) != 0 || hexValue == 0))
continue;
sb.Append(" <map value=\"0x").Append(hexValue.ToString("x", CultureInfo.InvariantCulture)).Append('"');

#if ES_BUILD_STANDALONE
string hexValueFormatted = hexValue.ToString("x", CultureInfo.InvariantCulture);
#else
hexValue.TryFormat(ulongHexScratch, out int charsWritten, "x");
Span<char> hexValueFormatted = ulongHexScratch.Slice(0, charsWritten);
#endif
sb.Append(" <map value=\"0x").Append(hexValueFormatted).Append('"');
WriteMessageAttrib(sb, "map", enumType.Name + "." + staticField.Name, staticField.Name);
sb.AppendLine("/>");
anyValuesWritten = true;
Expand Down Expand Up @@ -5667,7 +5692,13 @@ private string CreateManifestString()
{
sb.Append(" <keyword");
WriteNameAndMessageAttribs(sb, "keyword", keywordTab[keyword]);
sb.Append(" mask=\"0x").Append(keyword.ToString("x", CultureInfo.InvariantCulture)).AppendLine("\"/>");
#if ES_BUILD_STANDALONE
string keywordFormatted = keyword.ToString("x", CultureInfo.InvariantCulture);
#else
keyword.TryFormat(ulongHexScratch, out int charsWritten, "x");
Span<char> keywordFormatted = ulongHexScratch.Slice(0, charsWritten);
#endif
sb.Append(" mask=\"0x").Append(keywordFormatted).AppendLine("\"/>");
}
sb.AppendLine(" </keywords>");
}
Expand Down Expand Up @@ -5724,18 +5755,21 @@ private void WriteNameAndMessageAttribs(StringBuilder stringBuilder, string elem
}
private void WriteMessageAttrib(StringBuilder stringBuilder, string elementName, string name, string? value)
{
string key = elementName + "_" + name;
string? key = null;

// See if the user wants things localized.
if (resources != null)
{
// resource fallback: strings in the neutral culture will take precedence over inline strings
string? localizedString = resources.GetString(key, CultureInfo.InvariantCulture);
if (localizedString != null)
key = elementName + "_" + name;
if (resources.GetString(key, CultureInfo.InvariantCulture) is string localizedString)
value = localizedString;
}

if (value == null)
return;

key ??= elementName + "_" + name;
stringBuilder.Append(" message=\"$(string.").Append(key).Append(")\"");

if (stringTab.TryGetValue(key, out string? prevValue) && !prevValue.Equals(value))
Expand Down Expand Up @@ -5768,9 +5802,23 @@ private void WriteMessageAttrib(StringBuilder stringBuilder, string elementName,
return value;
}

private static string GetLevelName(EventLevel level)
private static void AppendLevelName(StringBuilder sb, EventLevel level)
{
return (((int)level >= 16) ? "" : "win:") + level.ToString();
if ((int)level < 16)
{
sb.Append("win:");
}

sb.Append(level switch // avoid boxing that comes from level.ToString()
{
EventLevel.LogAlways => nameof(EventLevel.LogAlways),
EventLevel.Critical => nameof(EventLevel.Critical),
EventLevel.Error => nameof(EventLevel.Error),
EventLevel.Warning => nameof(EventLevel.Warning),
EventLevel.Informational => nameof(EventLevel.Informational),
EventLevel.Verbose => nameof(EventLevel.Verbose),
_ => ((int)level).ToString()
});
}

#if FEATURE_MANAGED_ETW_CHANNELS
Expand Down Expand Up @@ -5851,15 +5899,15 @@ private string GetTaskName(EventTask task, string eventName)
return ret;
}

private string GetKeywords(ulong keywords, string eventName)
private void AppendKeywords(StringBuilder sb, ulong keywords, string eventName)
{
#if FEATURE_MANAGED_ETW_CHANNELS
// ignore keywords associate with channels
// See ValidPredefinedChannelKeywords def for more.
keywords &= ~ValidPredefinedChannelKeywords;
#endif

string ret = "";
bool appended = false;
for (ulong bit = 1; bit != 0; bit <<= 1)
{
if ((keywords & bit) != 0)
Expand All @@ -5877,12 +5925,19 @@ private string GetKeywords(ulong keywords, string eventName)
ManifestError(SR.Format(SR.EventSource_UndefinedKeyword, "0x" + bit.ToString("x", CultureInfo.CurrentCulture), eventName), true);
keyword = string.Empty;
}
if (ret.Length != 0 && keyword.Length != 0)
ret += " ";
ret += keyword;

if (keyword.Length != 0)
{
if (appended)
{
sb.Append(' ');
}

sb.Append(keyword);
appended = true;
}
}
}
return ret;
}

private string GetTypeName(Type type)
Expand Down

0 comments on commit e28dbe9

Please sign in to comment.