From e28dbe999dfef7d51b12a8407ddc9684abe9e672 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Wed, 18 Nov 2020 17:39:56 -0500 Subject: [PATCH] Remove some allocations from ManifestBuilder.CreateManifestString (#44532) For the RuntimeEventSource, this removes around 30K of allocation, though that's only ~3% of what gets allocated. --- .../System/Diagnostics/Tracing/EventSource.cs | 139 ++++++++++++------ 1 file changed, 97 insertions(+), 42 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs index e3d0c2b4a9e75..904c8169bf121 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs @@ -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); } @@ -5366,11 +5371,11 @@ public void StartEvent(string eventName, EventAttribute eventAttribute) numParams = 0; byteArrArgIndices = null; - events.Append(" Errors => errors; + public bool HasResources => resources != null; + /// /// When validating an event source it adds the error to the error collection. /// When not validating it throws an exception if runtimeCritical is "true". @@ -5516,6 +5535,10 @@ public void ManifestError(string msg, bool runtimeCritical = false) private string CreateManifestString() { +#if !ES_BUILD_STANDALONE + Span 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) @@ -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 @@ -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(" "); } sb.AppendLine(" "); @@ -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(" hexValueFormatted = ulongHexScratch.Slice(0, charsWritten); +#endif + sb.Append(" "); anyValuesWritten = true; @@ -5667,7 +5692,13 @@ private string CreateManifestString() { sb.Append(" "); +#if ES_BUILD_STANDALONE + string keywordFormatted = keyword.ToString("x", CultureInfo.InvariantCulture); +#else + keyword.TryFormat(ulongHexScratch, out int charsWritten, "x"); + Span keywordFormatted = ulongHexScratch.Slice(0, charsWritten); +#endif + sb.Append(" mask=\"0x").Append(keywordFormatted).AppendLine("\"/>"); } sb.AppendLine(" "); } @@ -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)) @@ -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 @@ -5851,7 +5899,7 @@ 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 @@ -5859,7 +5907,7 @@ private string GetKeywords(ulong keywords, string eventName) keywords &= ~ValidPredefinedChannelKeywords; #endif - string ret = ""; + bool appended = false; for (ulong bit = 1; bit != 0; bit <<= 1) { if ((keywords & bit) != 0) @@ -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)