diff options
Diffstat (limited to 'mcs/class/dlr/Runtime/Microsoft.Dynamic')
3 files changed, 295 insertions, 0 deletions
diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/DebugOptions.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/DebugOptions.cs new file mode 100644 index 0000000000..a3aac34473 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/DebugOptions.cs @@ -0,0 +1,76 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System.Security; +using System; + +namespace Microsoft.Scripting { + + /// <summary> + /// This class holds onto internal debugging options used in this assembly. + /// These options can be set via environment variables DLR_{option-name}. + /// Boolean options map "true" to true and other values to false. + /// + /// These options are for internal debugging only, and should not be + /// exposed through any public APIs. + /// </summary> + internal static class DebugOptions { + + private static bool ReadOption(string name) { +#if SILVERLIGHT + return false; +#else + string envVar = ReadString(name); + return envVar != null && envVar.ToLowerInvariant() == "true"; +#endif + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "name")] + private static bool ReadDebugOption(string name) { +#if DEBUG + return ReadOption(name); +#else + return false; +#endif + } + + private static string ReadString(string name) { +#if FEATURE_PROCESS + try { + return Environment.GetEnvironmentVariable("DLR_" + name); + } catch (SecurityException) { + return null; + } +#else + return null; +#endif + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "name")] + private static string ReadDebugString(string name) { +#if DEBUG + return ReadString(name); +#else + return null; +#endif + } + + private readonly static bool _trackPerformance = ReadDebugOption("TrackPerformance"); + + internal static bool TrackPerformance { + get { return _trackPerformance; } + } + } +}
\ No newline at end of file diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/MultiRuntimeAwareAttribute.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/MultiRuntimeAwareAttribute.cs new file mode 100644 index 0000000000..3b0cc25069 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/MultiRuntimeAwareAttribute.cs @@ -0,0 +1,34 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; +using System.Diagnostics; + +namespace Microsoft.Scripting { + /// <summary> + /// marks a field, class, or struct as being safe to have statics which can be accessed + /// from multiple runtimes. + /// + /// Static fields which are not read-only or marked with this attribute will be flagged + /// by a test which looks for state being shared between runtimes. Before applying this + /// attribute you should ensure that it is safe to share the state. This is typically + /// state which is lazy initialized or state which is caching values which are identical + /// in all runtimes and are immutable. + /// </summary> + [Conditional("DEBUG")] + [AttributeUsage(AttributeTargets.Field)] + public sealed class MultiRuntimeAwareAttribute : Attribute { + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/PerfTrack.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/PerfTrack.cs new file mode 100644 index 0000000000..622e41d092 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/PerfTrack.cs @@ -0,0 +1,185 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if FEATURE_CORE_DLR +using System.Linq.Expressions; +#else +using Microsoft.Scripting.Ast; +#endif + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using Microsoft.Scripting.Utils; +using System.Dynamic; +using System.IO; + +namespace Microsoft.Scripting { + /// <summary> + /// This class is useful for quickly collecting performance counts for expensive + /// operations. Usually this means operations involving either reflection or + /// code gen. Long-term we need to see if this can be plugged better into the + /// standard performance counter architecture. + /// </summary> + public static class PerfTrack { + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1717:OnlyFlagsEnumsShouldHavePluralNames")] // TODO: fix + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] // TODO: fix + public enum Categories { + /// <summary> + /// temporary categories for quick investigation, use a custom key if you + /// need to track multiple items, and if you want to keep it then create + /// a new Categories entry and rename all your temporary entries. + /// </summary> + Temporary, + ReflectedTypes, + Exceptions, // exceptions thrown + Properties, // properties got or set + Fields, // fields got or set + Methods, // methods called through MethodBase.Invoke()... + Compiler, // Methods compiled via the ReflectOptimizer + DelegateCreate, // we've created a new method for delegates + DictInvoke, // Dictionary accesses + OperatorInvoke, // Invoking an operator against a type + OverAllocate, // a spot where we have an un-ideal algorithm that needs to allocate more than necessary + Rules, // related to rules / actions. + RuleEvaluation, // a rule was evaluated + Binding, // a rule was bound + BindingSlow, + BindingFast, + BindingTarget, // a rule was bound against a target of a specific type + Count + } + + [MultiRuntimeAware] + private static int totalEvents; + private static readonly Dictionary<Categories, Dictionary<string, int>> _events = MakeEventsDictionary(); + private static readonly Dictionary<Categories, int> summaryStats = new Dictionary<Categories, int>(); + + private static Dictionary<Categories, Dictionary<string, int>> MakeEventsDictionary() { + Dictionary<Categories, Dictionary<string, int>> result = new Dictionary<Categories, Dictionary<string, int>>(); + + // We do not use Enum.GetValues here since it is not available in SILVERLIGHT + for (int i = 0; i <= (int)Categories.Count; i++) { + result[(Categories)i] = new Dictionary<string, int>(); + } + + return result; + } + +#if FEATURE_BASIC_CONSOLE + public static void DumpHistogram<TKey>(IDictionary<TKey, int> histogram) { + DumpHistogram(histogram, Console.Out); + } + + public static void DumpStats() { + DumpStats(Console.Out); + } +#endif + + public static void DumpHistogram<TKey>(IDictionary<TKey, int> histogram, TextWriter output) { + var keys = ArrayUtils.MakeArray(histogram.Keys); + var values = ArrayUtils.MakeArray(histogram.Values); + +#if !WIN8 // TODO: + Array.Sort(values, keys); +#endif + for (int i = 0; i < keys.Length; i++) { + output.WriteLine("{0} {1}", keys[i], values[i]); + } + } + + public static void AddHistograms<TKey>(IDictionary<TKey, int> result, IDictionary<TKey, int> addend) { + foreach (var entry in addend) { + int value; + result[entry.Key] = entry.Value + (result.TryGetValue(entry.Key, out value) ? value : 0); + } + } + + public static void IncrementEntry<TKey>(IDictionary<TKey, int> histogram, TKey key) { + int value; + histogram.TryGetValue(key, out value); + histogram[key] = value + 1; + } + + public static void DumpStats(TextWriter output) { + if (totalEvents == 0) return; + + // numbers from AMD Opteron 244 1.8 Ghz, 2.00GB of ram, + // running on IronPython 1.0 Beta 4 against Whidbey RTM. + const double CALL_TIME = 0.0000051442355; + const double THROW_TIME = 0.000025365656; + const double FIELD_TIME = 0.0000018080093; + + output.WriteLine(); + output.WriteLine("---- Performance Details ----"); + output.WriteLine(); + + foreach (KeyValuePair<Categories, Dictionary<string, int>> kvpCategories in _events) { + if (kvpCategories.Value.Count > 0) { + output.WriteLine("Category : " + kvpCategories.Key); + DumpHistogram(kvpCategories.Value, output); + output.WriteLine(); + } + } + + output.WriteLine(); + output.WriteLine("---- Performance Summary ----"); + output.WriteLine(); + double knownTimes = 0; + foreach (KeyValuePair<Categories, int> kvp in summaryStats) { + switch (kvp.Key) { + case Categories.Exceptions: + output.WriteLine("Total Exception ({0}) = {1} (throwtime = ~{2} secs)", kvp.Key, kvp.Value, kvp.Value * THROW_TIME); + knownTimes += kvp.Value * THROW_TIME; + break; + case Categories.Fields: + output.WriteLine("Total field = {0} (time = ~{1} secs)", kvp.Value, kvp.Value * FIELD_TIME); + knownTimes += kvp.Value * FIELD_TIME; + break; + case Categories.Methods: + output.WriteLine("Total calls = {0} (calltime = ~{1} secs)", kvp.Value, kvp.Value * CALL_TIME); + knownTimes += kvp.Value * CALL_TIME; + break; + //case Categories.Properties: + default: + output.WriteLine("Total {1} = {0}", kvp.Value, kvp.Key); + break; + } + } + + output.WriteLine(); + output.WriteLine("Total Known Times: {0}", knownTimes); + } + + [Conditional("DEBUG")] + public static void NoteEvent(Categories category, object key) { + if (!DebugOptions.TrackPerformance) return; + + Dictionary<string, int> categoryEvents = _events[category]; + totalEvents++; + lock (categoryEvents) { + string name = key.ToString(); + Exception ex = key as Exception; + if (ex != null) name = ex.GetType().ToString(); + int v; + if (!categoryEvents.TryGetValue(name, out v)) categoryEvents[name] = 1; + else categoryEvents[name] = v + 1; + + if (!summaryStats.TryGetValue(category, out v)) summaryStats[category] = 1; + else summaryStats[category] = v + 1; + } + } + } +} |