diff --git a/Engine/StackResolver.cs b/Engine/StackResolver.cs index 7789660..08358d1 100644 --- a/Engine/StackResolver.cs +++ b/Engine/StackResolver.cs @@ -29,8 +29,8 @@ public class StackResolver : IDisposable { private static readonly Regex rgxAlreadySymbolizedFrame = new (@"((?\d+)\s+)*(?\w+)(\.(dll|exe))*!(?.+?)\s*\+\s*(0[xX])*(?[0-9a-fA-F]+)\s*", rgxOptions); private static readonly Regex rgxmoduleaddress = new (@"^\s*(?.+)(\t+| +)(?(0x)?[0-9a-fA-F`]+)\s*$", RegexOptions.Multiline); - public Task, List>> GetDistinctXELFieldsAsync(string[] xelFiles, int eventsToSample, CancellationTokenSource cts) { - return XELHelper.GetDistinctXELActionsFieldsAsync(xelFiles, eventsToSample, cts); + public Task, List>> GetDistinctXELFieldsAsync(string[] xelFiles, int eventsToSample) { + return XELHelper.GetDistinctXELActionsFieldsAsync(xelFiles, eventsToSample); } /// Public method which to help import XEL files diff --git a/Engine/XELHelper.cs b/Engine/XELHelper.cs index ff32d32..16e5ee8 100644 --- a/Engine/XELHelper.cs +++ b/Engine/XELHelper.cs @@ -78,29 +78,27 @@ await xeStream.ReadEventStream(evt => { }); } - internal async static Task, List>> GetDistinctXELActionsFieldsAsync(string[] xelFiles, int eventsToSampleFromEachFile, CancellationTokenSource cts) { + internal async static Task, List>> GetDistinctXELActionsFieldsAsync(string[] xelFiles, int eventsToSampleFromEachFile) { return await Task.Run(async () => { Contract.Requires(xelFiles != null && eventsToSampleFromEachFile > 0); var allActions = new HashSet(); var allFields = new HashSet(); - bool internalCancel = false; foreach (var file in xelFiles) { var numEvents = 0; var xeStream = new XEFileEventStreamer(file); try { + // If preceeding file had issued an "internal cancel" (due to number of sampled events reached) + // then create a new CTS to ensure subsequent files (if any) are also sampled correctly. + using var cts = new CancellationTokenSource(); await xeStream.ReadEventStream(evt => { - if (Interlocked.Increment(ref numEvents) > eventsToSampleFromEachFile) { - internalCancel = true; - cts.Cancel(); - } + if (Interlocked.Increment(ref numEvents) > eventsToSampleFromEachFile) cts.Cancel(); lock (allActions) evt.Actions.Select(action => allActions.Add(action.Key)).Count(); lock (allFields) evt.Fields.Select(field => allFields.Add(field.Key)).Count(); return Task.CompletedTask; }, cts.Token); } catch (AggregateException e) { - if (e.InnerException is OperationCanceledException) if (!internalCancel) return new Tuple, List>(new List(), new List()); - else throw; - } catch (OperationCanceledException) { if (!internalCancel) return new Tuple, List>(new List(), new List()); } + if (e.InnerException is not OperationCanceledException) throw; + } catch (OperationCanceledException) { /* nothing to do, as cancel the operation at the end of sampling */ } } return new Tuple, List>(allActions.OrderBy(k => k).ToList(), allFields.OrderBy(k => k).ToList()); diff --git a/GUI/MainForm.cs b/GUI/MainForm.cs index 420ce6f..9de5808 100644 --- a/GUI/MainForm.cs +++ b/GUI/MainForm.cs @@ -223,9 +223,8 @@ private async void CallStackInput_DragDrop(object sender, DragEventArgs e) { private async Task> GetUserSelectedXEFieldsAsync(string[] fileNames) { using var fieldsListDialog = new FieldSelection(); - using var cts = new CancellationTokenSource(); fieldsListDialog.Text = "Select relevant XEvent fields"; - var xeEventItems = await this._resolver.GetDistinctXELFieldsAsync(fileNames, 1000, cts); + var xeEventItems = await this._resolver.GetDistinctXELFieldsAsync(fileNames, 1000); if (xeEventItems.Item1.Count + xeEventItems.Item2.Count == 0) return new List(); fieldsListDialog.AllActions = xeEventItems.Item1; fieldsListDialog.AllFields = xeEventItems.Item2; diff --git a/Tests/Tests.cs b/Tests/Tests.cs index d9d4f36..1d06404 100644 --- a/Tests/Tests.cs +++ b/Tests/Tests.cs @@ -305,8 +305,7 @@ private string PrepareLargeXEventInput() { [TestMethod][TestCategory("Unit")] public async Task XELActionsAndFieldsAsync() { using var csr = new StackResolver(); - using var cts = new CancellationTokenSource(); - var ret = await csr.GetDistinctXELFieldsAsync(new[] { @"..\..\..\Tests\TestCases\ImportXEL\xe_wait_completed_0_132353446563350000.xel" }, 1000, cts); + var ret = await csr.GetDistinctXELFieldsAsync(new[] { @"..\..\..\Tests\TestCases\ImportXEL\xe_wait_completed_0_132353446563350000.xel" }, 5); Assert.AreEqual(1, ret.Item1.Count); // just the callstack action Assert.AreEqual("callstack", ret.Item1.First()); // verify the name Assert.AreEqual(5, ret.Item2.Count); // 5 fields @@ -316,8 +315,7 @@ private string PrepareLargeXEventInput() { [TestMethod][TestCategory("Unit")] public async Task XELActionsAndFieldsAsyncMultipleFiles() { using var csr = new StackResolver(); - using var cts = new CancellationTokenSource(); - var ret = await csr.GetDistinctXELFieldsAsync(new[] { @"..\..\..\Tests\TestCases\ImportXEL\xe_wait_completed_0_132353446563350000.xel", @"..\..\..\Tests\TestCases\ImportXEL\XESpins_0_131627061603030000.xel" }, 1000, cts); + var ret = await csr.GetDistinctXELFieldsAsync(new[] { @"..\..\..\Tests\TestCases\ImportXEL\xe_wait_completed_0_132353446563350000.xel", @"..\..\..\Tests\TestCases\ImportXEL\XESpins_0_131627061603030000.xel" }, 5); Assert.AreEqual(1, ret.Item1.Count); // just the callstack action Assert.AreEqual("callstack", ret.Item1.First()); // verify the name Assert.AreEqual(9, ret.Item2.Count); // 9 fields in total across the 2 XEL files @@ -776,15 +774,6 @@ private string PrepareLargeXEventInput() { Assert.AreEqual(0, xelTask.Result.Item1); Assert.AreEqual(StackResolver.OperationCanceled, xelTask.Result.Item2); - using var cts2 = new CancellationTokenSource(); - var xelFieldsTask = csr.GetDistinctXELFieldsAsync(new[] { @"..\..\..\Tests\TestCases\ImportXEL\XESpins_0_131627061603030000.xel" }, int.MaxValue, cts2); - while (true) { - if (xelFieldsTask.Wait(StackResolver.OperationWaitIntervalMilliseconds)) break; - cts2.Cancel(); - } - Assert.AreEqual(0, xelFieldsTask.Result.Item1.Count); - Assert.AreEqual(0, xelFieldsTask.Result.Item2.Count); - Assert.IsTrue(csr.ProcessBaseAddresses(@"c:\mssql\binn\sqldk.dll 00000001`00400000")); var xeventInput = PrepareLargeXEventInput().ToString(); using var cts3 = new CancellationTokenSource();