From 6a90ec81b80d80795701b05fb5bccbbcfb3f1b24 Mon Sep 17 00:00:00 2001 From: Arvind Shyamsundar <16342666+arvindshmicrosoft@users.noreply.github.com> Date: Thu, 5 Jun 2025 23:54:37 -0700 Subject: [PATCH] Resolve inconsistency in newline handling * Ensure consistent newline before each "slot" in histogram cases. * Handle trailing spaces in single-line multiple frames input. * Add new test for histogram fn+offset case; minor update to existing test to reflect the desired outcome. * Unrelated change - default GUI to include function offsets in output. * Bump latest release timestamp. --- Engine/ModuleInfoHelper.cs | 2 +- Engine/StackResolver.cs | 4 ++-- GUI/MainForm.Designer.cs | 2 ++ Tests/Tests.cs | 14 +++++++++++++- latestrelease.txt | 2 +- 5 files changed, 19 insertions(+), 5 deletions(-) diff --git a/Engine/ModuleInfoHelper.cs b/Engine/ModuleInfoHelper.cs index 4737da1..96ff1ae 100644 --- a/Engine/ModuleInfoHelper.cs +++ b/Engine/ModuleInfoHelper.cs @@ -134,7 +134,7 @@ await Task.Run(() => Parallel.ForEach(listOfCallStacks, currItem => { // pass-through this line as it is either non-XML, 0-length or whitespace-only outCallstack.AppendLine(line); } - currItem.Callstack = outCallstack.ToString(); + currItem.Callstack = outCallstack.ToString().Trim(); } })); diff --git a/Engine/StackResolver.cs b/Engine/StackResolver.cs index 08358d1..6f6a080 100644 --- a/Engine/StackResolver.cs +++ b/Engine/StackResolver.cs @@ -382,7 +382,7 @@ public async Task ResolveCallstacksAsync(List listOfCallSt foreach (var currstack in listOfCallStacks) { if (cts.IsCancellationRequested) { StatusMessage = OperationCanceled; PercentComplete = 0; return OperationCanceled; } - if (!string.IsNullOrEmpty(currstack.Resolvedstack)) finalCallstack.Append(currstack.Resolvedstack); + if (!string.IsNullOrEmpty(currstack.Resolvedstack)) finalCallstack.AppendLine(currstack.Resolvedstack); else if (!string.IsNullOrEmpty(currstack.Callstack)) { finalCallstack = new StringBuilder("WARNING: No output to show. This may indicate an internal error!"); break; @@ -477,7 +477,7 @@ public async Task> GetListofCallStacksAsync(string inputCalls string callstackText = string.Empty; if (reader.ReadToDescendant("value")) { reader.Read(); - if (XmlNodeType.Text == reader.NodeType || XmlNodeType.CDATA == reader.NodeType) callstackText = reader.Value; + if (XmlNodeType.Text == reader.NodeType || XmlNodeType.CDATA == reader.NodeType) callstackText = reader.Value.Trim(); } if (string.IsNullOrEmpty(callstackText)) throw new XmlException(); allStacks.Add(new StackDetails(callstackText, framesOnSingleLine, annotation, $"Slot_{stacknum}\t[count:{slotcount}]:")); diff --git a/GUI/MainForm.Designer.cs b/GUI/MainForm.Designer.cs index b11f2ca..5e5462b 100644 --- a/GUI/MainForm.Designer.cs +++ b/GUI/MainForm.Designer.cs @@ -360,6 +360,8 @@ private void InitializeComponent() { this.includeOffsets.AccessibleDescription = "Whether to include offsets into functions in the output"; this.includeOffsets.AccessibleName = "includeOffsets"; this.includeOffsets.AutoSize = true; + this.includeOffsets.Checked = true; + this.includeOffsets.CheckState = System.Windows.Forms.CheckState.Checked; this.includeOffsets.Location = new System.Drawing.Point(462, 41); this.includeOffsets.Margin = new System.Windows.Forms.Padding(2); this.includeOffsets.Name = "includeOffsets"; diff --git a/Tests/Tests.cs b/Tests/Tests.cs index 6a8a09e..d85b02c 100644 --- a/Tests/Tests.cs +++ b/Tests/Tests.cs @@ -651,6 +651,18 @@ private string PrepareLargeXEventInput() { Assert.AreEqual(expected.Trim(), ret.Trim()); } + /// End-to-end test with XE histogram target and module+offset frames. + [TestMethod][TestCategory("Unit")] + public async Task E2EHistogramOffsets() { + using var csr = new StackResolver(); + using var cts = new CancellationTokenSource(); + var pdbPath = @"..\..\..\Tests\TestCases\TestOrdinal"; + var input = "\r\n \r\n sqldk.dll+40609\r\nsqldk.dll+40609\r\n \r\n\r\n sqldk.dll+40609\r\nsqldk.dll+40609\r\n \r\n"; + var ret = await csr.ResolveCallstacksAsync(await csr.GetListofCallStacksAsync(input, true, cts), pdbPath, false, null, true, false, false, true, false, false, null, cts); + var expected = "Slot_0 [count:108633]:\r\n\r\nsqldk!MemoryClerkInternal::AllocatePagesWithFailureMode+644\r\nsqldk!MemoryClerkInternal::AllocatePagesWithFailureMode+644\r\n\r\nSlot_1\t[count:108631]:\r\n\r\nsqldk!MemoryClerkInternal::AllocatePagesWithFailureMode+644\r\nsqldk!MemoryClerkInternal::AllocatePagesWithFailureMode+644"; + Assert.AreEqual(expected.Trim(), ret.Trim()); + } + [TestMethod][TestCategory("Unit")] public async Task E2ESymSrvXMLFramesMultiHistogram() { using var csr = new StackResolver(); using var cts = new CancellationTokenSource(); @@ -678,7 +690,7 @@ private string PrepareLargeXEventInput() { "Annotation for histogram #2 0x00007FFEAC0F80CF 0x00007FFEAC1EE447 0x00007FFEAC1EE6F5"; var ret = await csr.ResolveCallstacksAsync(await csr.GetListofCallStacksAsync(input, true, cts), pdbPath, false, null, false, false, false, true, false, false, null, cts); - var expected = "Annotation for histogram #1\r\nSlot_0 [count:5]:\r\n\r\nsqldk!XeSosPkg::spinlock_backoff::Publish+425\r\nsqldk!SpinlockBase::Sleep+182\r\nsqlmin!Spinlock<143,7,1>::SpinToAcquireWithExponentialBackoff+363\r\nsqlmin!lck_lockInternal+2042\r\nAnnotation for histogram #2\r\nSlot_1 [count:5]:\r\n\r\nsqlmin!lck_lockInternal+2042\r\nsqlmin!MDL::LockGenericLocal+382\r\nsqlmin!MDL::LockGenericIdsLocal+101"; + var expected = "Annotation for histogram #1\r\nSlot_0 [count:5]:\r\n\r\nsqldk!XeSosPkg::spinlock_backoff::Publish+425\r\nsqldk!SpinlockBase::Sleep+182\r\nsqlmin!Spinlock<143,7,1>::SpinToAcquireWithExponentialBackoff+363\r\nsqlmin!lck_lockInternal+2042\r\n\r\nAnnotation for histogram #2\r\nSlot_1 [count:5]:\r\n\r\nsqlmin!lck_lockInternal+2042\r\nsqlmin!MDL::LockGenericLocal+382\r\nsqlmin!MDL::LockGenericIdsLocal+101"; Assert.AreEqual(expected.Trim(), ret.Trim()); } diff --git a/latestrelease.txt b/latestrelease.txt index 71c99ff..c80d726 100644 --- a/latestrelease.txt +++ b/latestrelease.txt @@ -1 +1 @@ -2025-05-28 00:00 +2025-06-06 00:00