Skip to content

Commit

Permalink
OpenLog event resolving is now multi threaded
Browse files Browse the repository at this point in the history
  • Loading branch information
jschick04 authored and bill-long committed Mar 7, 2024
1 parent a020617 commit 1a670cc
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 34 deletions.
96 changes: 63 additions & 33 deletions src/EventLogExpert.UI/Store/EventLog/EventLogEffects.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using EventLogExpert.UI.Store.StatusBar;
using Fluxor;
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Concurrent;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Diagnostics.Eventing.Reader;
Expand Down Expand Up @@ -112,9 +113,9 @@ public async Task HandleOpenLog(EventLogAction.OpenLog action, IDispatcher dispa
return;
}

EventLogReader reader = action.LogType == LogType.Live ?
new EventLogReader(action.LogName, PathType.LogName) :
new EventLogReader(action.LogName, PathType.FilePath);
EventLogQuery eventLog = action.LogType == LogType.Live ?
new EventLogQuery(action.LogName, PathType.LogName) :
new EventLogQuery(action.LogName, PathType.FilePath);

var activityId = Guid.NewGuid();

Expand All @@ -125,47 +126,78 @@ public async Task HandleOpenLog(EventLogAction.OpenLog action, IDispatcher dispa
var sw = new Stopwatch();
sw.Start();

List<DisplayEventModel> events = [];
HashSet<int> eventIdsAll = [];
HashSet<Guid?> eventActivityIdsAll = [];
HashSet<string> eventProviderNamesAll = [];
HashSet<string> eventTaskNamesAll = [];
HashSet<string> eventKeywordNamesAll = [];
EventRecord? lastEvent = null;

await Task.Run(() =>
int batchSize = 200;
bool doneReading = false;
ConcurrentQueue<EventRecord> records = new();
ConcurrentQueue<DisplayEventModel> events = new();

using Timer timer = new(
s => { dispatcher.Dispatch(new StatusBarAction.SetEventsLoading(activityId, events.Count)); },
null,
TimeSpan.Zero,
TimeSpan.FromSeconds(1));

// Don't need to wait on this since we are waiting for doneReading in the resolver tasks
_ = Task.Run(() =>
{
using var reader = new EventLogReader(eventLog);

int count = 0;
while (reader.ReadEvent() is { } e)
{
while (reader.ReadEvent() is { } e)
action.Token.ThrowIfCancellationRequested();

if (count % batchSize == 0)
{
action.Token.ThrowIfCancellationRequested();
records.Enqueue(e);
}

count++;

lastEvent = e;
var resolved = eventResolver.Resolve(e, action.LogName);
eventIdsAll.Add(resolved.Id);
eventActivityIdsAll.Add(resolved.ActivityId);
eventProviderNamesAll.Add(resolved.Source);
eventTaskNamesAll.Add(resolved.TaskCategory);
eventKeywordNamesAll.UnionWith(resolved.KeywordsDisplayNames);
lastEvent = e;
}

events.Add(resolved);
doneReading = true;
}, action.Token);

await Parallel.ForEachAsync(
[0, 1],
action.Token,
(_, token) =>
{
using var reader = new EventLogReader(eventLog);

if (sw.ElapsedMilliseconds > 1000)
while (records.TryDequeue(out EventRecord? @event) || !doneReading)
{
token.ThrowIfCancellationRequested();

if (@event is null) { continue; }

reader.Seek(@event.Bookmark);

for (int i = 0; i < batchSize; i++)
{
sw.Restart();
dispatcher.Dispatch(new StatusBarAction.SetEventsLoading(activityId, events.Count));
@event = reader.ReadEvent();

if (@event is null) { break; }

events.Enqueue(eventResolver.Resolve(@event, action.LogName));
}
}
},
action.Token);

return ValueTask.CompletedTask;
});

dispatcher.Dispatch(new EventLogAction.LoadEvents(
logData,
events.AsReadOnly(),
[.. eventIdsAll],
[.. eventActivityIdsAll],
[.. eventProviderNamesAll],
[.. eventTaskNamesAll],
[.. eventKeywordNamesAll]));
events.ToList().AsReadOnly(),
events.Select(e => e.Id).ToImmutableHashSet(),
events.Select(e => e.ActivityId).ToImmutableHashSet(),
events.Select(e => e.Source).ToImmutableHashSet(),
events.Select(e => e.TaskCategory).ToImmutableHashSet(),
events.SelectMany(e => e.KeywordsDisplayNames).ToImmutableHashSet()));

dispatcher.Dispatch(new StatusBarAction.SetEventsLoading(activityId, 0));

Expand All @@ -182,8 +214,6 @@ await Task.Run(() =>
finally
{
dispatcher.Dispatch(new StatusBarAction.SetResolverStatus(string.Empty));

reader.Dispose();
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/EventLogExpert/Components/DetailsPane.razor.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

border-top: solid var(--background-darkgray);

&[data-toggle="false"] {
&[data-toggle="false"] {
height: auto !important;
min-height: 0 !important;

Expand Down Expand Up @@ -55,6 +55,8 @@
margin: 0;
height: 100%;
overflow-y: auto;
overflow-x: hidden;
text-wrap: pretty;
white-space: pre-wrap;
}

Expand Down

0 comments on commit 1a670cc

Please sign in to comment.