From b5d610976464bf8ba245bb04ee89f735dd53ede4 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 15 Feb 2019 21:03:43 -0800 Subject: [PATCH] Set up event source for easier perf investigations --- .../PerfNetFramework/BenchmarkEventSource.cs | 75 +++++++++++++++++++ sandbox/PerfNetFramework/Program.cs | 30 +++++++- sandbox/PerfNetFramework/README.md | 26 +++++++ 3 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 sandbox/PerfNetFramework/BenchmarkEventSource.cs create mode 100644 sandbox/PerfNetFramework/README.md diff --git a/sandbox/PerfNetFramework/BenchmarkEventSource.cs b/sandbox/PerfNetFramework/BenchmarkEventSource.cs new file mode 100644 index 00000000..a2fbd237 --- /dev/null +++ b/sandbox/PerfNetFramework/BenchmarkEventSource.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.Tracing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PerfNetFramework +{ + [EventSource(Name = "MessagePack-Benchmark")] + internal sealed class BenchmarkEventSource : EventSource + { + private const int MessagePackSerializeStartEvent = 1; + private const int MessagePackSerializeStopEvent = 2; + private const int MessagePackDeserializeStartEvent = 3; + private const int MessagePackDeserializeStopEvent = 4; + private const int MessagePackSessionStartEvent = 5; + private const int MessagePackSessionStopEvent = 6; + + internal static readonly BenchmarkEventSource Instance = new BenchmarkEventSource(); + + private BenchmarkEventSource() { } + + /// + /// Marks the start of a serialization benchmark. + /// + /// The library performing the serialization. + [Event(MessagePackSerializeStartEvent, Task = Tasks.Serialize, Opcode = EventOpcode.Start)] + public void Serialize(string impl) + { + this.WriteEvent(MessagePackSerializeStartEvent, impl); + } + + [Event(MessagePackSerializeStopEvent, Task = Tasks.Serialize, Opcode = EventOpcode.Stop)] + public void SerializeEnd() + { + this.WriteEvent(MessagePackSerializeStopEvent); + } + + /// + /// Marks the start of a deserialization benchmark. + /// + /// The library performing the serialization. + [Event(MessagePackDeserializeStartEvent, Task = Tasks.Deserialize, Opcode = EventOpcode.Start)] + public void Deserialize(string impl) + { + this.WriteEvent(MessagePackDeserializeStartEvent, impl); + } + + [Event(MessagePackDeserializeStopEvent, Task = Tasks.Deserialize, Opcode = EventOpcode.Stop)] + public void DeserializeEnd() + { + this.WriteEvent(MessagePackDeserializeStopEvent); + } + + [Event(MessagePackSessionStartEvent, Task = Tasks.Session, Opcode = EventOpcode.Start)] + public void Session(int count) + { + this.WriteEvent(MessagePackSessionStartEvent, count); + } + + [Event(MessagePackSessionStopEvent, Task = Tasks.Session, Opcode = EventOpcode.Stop)] + public void SessionEnd() + { + this.WriteEvent(MessagePackSessionStopEvent); + } + + internal static class Tasks + { + internal const EventTask Session = (EventTask)1; + internal const EventTask Serialize = (EventTask)2; + internal const EventTask Deserialize = (EventTask)3; + } + } +} diff --git a/sandbox/PerfNetFramework/Program.cs b/sandbox/PerfNetFramework/Program.cs index 820b3beb..d1f81007 100644 --- a/sandbox/PerfNetFramework/Program.cs +++ b/sandbox/PerfNetFramework/Program.cs @@ -14,7 +14,7 @@ using Newtonsoft.Json; using System.Text; using System.IO.Compression; -namespace PerfnetFramework +namespace PerfNetFramework { [ZeroFormattable] [ProtoBuf.ProtoContract] @@ -55,6 +55,8 @@ namespace PerfnetFramework class Program { + internal static bool deserializing; + static void Main(string[] args) { var p = new Person @@ -76,9 +78,14 @@ namespace PerfnetFramework }) .ToArray(); + BenchmarkEventSource.Instance.Session(1); Benchmark(p); + BenchmarkEventSource.Instance.SessionEnd(); + Console.WriteLine(); + BenchmarkEventSource.Instance.Session(l.Length); Benchmark(l); + BenchmarkEventSource.Instance.SessionEnd(); } static void Benchmark(T target) @@ -99,6 +106,8 @@ namespace PerfnetFramework Console.WriteLine(); Console.WriteLine("Serialize::"); + deserializing = false; + byte[] data = null; byte[] data0 = null; byte[] data1 = null; @@ -212,6 +221,7 @@ namespace PerfnetFramework Console.WriteLine(); Console.WriteLine("Deserialize::"); + deserializing = true; using (new Measure("MsgPack-Cli")) { @@ -344,12 +354,30 @@ namespace PerfnetFramework { this.label = label; System.GC.Collect(2, GCCollectionMode.Forced, blocking: true); + if (!Program.deserializing) + { + BenchmarkEventSource.Instance.Serialize(label); + } + else + { + BenchmarkEventSource.Instance.Deserialize(label); + } + this.sw = Stopwatch.StartNew(); } public void Dispose() { sw.Stop(); + if (!Program.deserializing) + { + BenchmarkEventSource.Instance.SerializeEnd(); + } + else + { + BenchmarkEventSource.Instance.DeserializeEnd(); + } + Console.WriteLine($"{ label,20} {sw.Elapsed.TotalMilliseconds} ms"); System.GC.Collect(2, GCCollectionMode.Forced, blocking: true); diff --git a/sandbox/PerfNetFramework/README.md b/sandbox/PerfNetFramework/README.md new file mode 100644 index 00000000..3c202c2b --- /dev/null +++ b/sandbox/PerfNetFramework/README.md @@ -0,0 +1,26 @@ +# Performance analysis + +Build and use the release configuration of the project so you're measuring real perf with optimizations turned on: + + dotnet build -c release .\sandbox\PerfNetFramework\ + +Use [PerfView](https://github.com/Microsoft/perfview/blob/master/documentation/Downloading.md) to analyze performance +to look for opportunities to improve. +When collecting ETL traces, use these settings in the Collect->Run dialog: + +| Setting | Value | +|-------------|-------| +| Command | `dotnet run -c release -p .\sandbox\PerfNetFramework\ -f net461 --no-build` +| Current Dir | `d:\git\messagepack-csharp` (or wherever your enlistment is) +| Additional Providers | `*MessagePack-Benchmark` +| No V3.X NGen | Checked + +Start your investigation using the Events window to find the scenario that you're interested in, +with these settings: + +| Setting | Value | +|------------|-------| +| Filter | `MessagePack` +| Columns to display | `count DURATION_MSEC impl` + +Select the two `Time MSec` values that bound the scenario you're interested in, right-click and select CPU Stacks.