Skip to content

Commit

Permalink
Remove some allocations from ManifestBuilder.CreateManifestString
Browse files Browse the repository at this point in the history
For the RuntimeEventSource, this removes around 30K of allocation, though that's only ~3% of what gets allocated.
  • Loading branch information
stephentoub committed Nov 12, 2020
1 parent 731dee4 commit 9678357
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 9678357

Please sign in to comment.