Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
ebd4670
wip: tracelog support for streaming an eventpipe source
vaind May 3, 2023
a9433c5
tracelog streaming fixes
vaind May 4, 2023
392c9fa
TraceLog support for initial rundown session
vaind May 19, 2023
6286887
fix stacktrace resolution on system frames
vaind May 23, 2023
f714892
feat: realtime streaming without queue
vaind May 30, 2023
382b8fe
update CreateFromEventPipeEventSource to support providing preloaded…
vaind May 30, 2023
4db0a45
review changes
vaind Jun 7, 2023
f890e71
review changes
vaind Aug 3, 2023
dbd71ff
test: TraceLog StreamingSession
vaind Aug 4, 2023
f1fcf81
fix CI
vaind Aug 9, 2023
3c65579
test: fix not disposing
vaind Aug 9, 2023
f5b49e4
update test dependencies
vaind Aug 9, 2023
53024ea
wip: find crashing test
vaind Aug 9, 2023
bed3d38
Merge branch 'main' into feat/eventpipe-tracelog-streaming
vaind Mar 20, 2024
68c1081
use net8 in testutils
vaind Mar 20, 2024
b2bb4e5
roll back debug assert change in tracelog
vaind Mar 25, 2024
36d2e2c
fix: clean up termporary data structures for realtime eventpipe source
vaind May 23, 2024
69a09db
Merge remote-tracking branch 'origin/main' into feat/eventpipe-tracel…
vaind May 23, 2024
fee63f9
chore: roll back some changes
vaind May 23, 2024
5153769
docs
vaind May 23, 2024
44c8fee
Merge branch 'main' into feat/eventpipe-tracelog-streaming
vaind Jun 6, 2024
2270d69
set NuspecProperties
vaind Jun 27, 2024
d161492
Merge branch 'main' into feat/eventpipe-tracelog-streaming
vaind Jun 27, 2024
e21e9c7
fix traceevent.csproj
vaind Jun 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
review changes
  • Loading branch information
vaind committed Aug 9, 2023
commit f890e712f1537699acea94c3abcf3d47bebed861
6 changes: 3 additions & 3 deletions src/TraceEvent/TraceEvent.Tests/Parsing/EventPipeParsing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class EventPipeParsing : EventPipeTestBase
private class EventRecord
{
public int TotalCount;
public string FirstSeriazliedSample;
public string FirstSerializedSample;
}

private class EventStatistics
Expand All @@ -41,7 +41,7 @@ public void Record(string eventName, TraceEvent data)
Records[eventName] = new EventRecord()
{
TotalCount = 1,
FirstSeriazliedSample = new String(data.ToString().Replace("\n", "\\n").Replace("\r", "\\r").Take(1000).ToArray())
FirstSerializedSample = new String(data.ToString().Replace("\n", "\\n").Replace("\r", "\\r").Take(1000).ToArray())
};
}
}
Expand Down Expand Up @@ -619,7 +619,7 @@ private void ValidateEventStatistics(EventStatistics eventStatistics, string eve
StringBuilder sb = new StringBuilder(1024 * 1024);
foreach (var item in eventStatistics.Records)
{
sb.AppendLine($"{item.Key}, {item.Value.TotalCount}, {item.Value.FirstSeriazliedSample}");
sb.AppendLine($"{item.Key}, {item.Value.TotalCount}, {item.Value.FirstSerializedSample}");
}

string actual = sb.ToString();
Expand Down
80 changes: 36 additions & 44 deletions src/TraceEvent/TraceLog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -184,37 +184,61 @@ public static TraceLogEventSource CreateFromTraceEventSession(TraceEventSession
/// the .Log Property) which lets you get at aggregated information (Processes, threads, images loaded, and perhaps most
/// importantly TraceEvent.CallStack() will work. Thus you can get real time stacks from events).
/// </summary>
/// <param name="rundownSession">
/// If given, the rundownSession is used to initialize module and method information and then the session is closed.
/// This only makes sense in realtime sessions when you need to resolve function names.
/// <param name="rundownConfiguration">
/// If enabled, a rundown is triggered immediately as a separate session.
/// This is used to initialize module and method information and then the session is closed.
/// This only makes sense in realtime sessions when you need to resolve function names during the session.
/// </param>
/// <example>
/// var client = new DiagnosticsClient(Process.GetCurrentProcess().Id);
/// using var rundownSession = client.StartEventPipeSession(
/// new EventPipeProvider(ClrTraceEventParser.ProviderName, EventLevel.Informational, (long) ClrTraceEventParser.Keywords.Default),
/// requestRundown: true
/// );
/// EventPipeProvider[] providers = new[]
/// { new EventPipeProvider(ClrTraceEventParser.ProviderName, EventLevel.Informational, (long) ClrTraceEventParser.Keywords.Default),
/// new EventPipeProvider(SampleProfilerTraceEventParser.ProviderName, EventLevel.Informational),
/// };
/// var session = client.StartEventPipeSession(providers, requestRundown: false);
/// var eventSource = TraceLog.CreateFromEventPipeSession(session, rundownSession);
/// var eventSource = TraceLog.CreateFromEventPipeSession(session, TraceLog.EventPipeRundownConfiguration.Enable(client));
/// eventSource.Process();
/// </example>
public static TraceLogEventSource CreateFromEventPipeSession(EventPipeSession session, EventPipeSession rundownSession = null)
public static TraceLogEventSource CreateFromEventPipeSession(EventPipeSession session, EventPipeRundownConfiguration rundownConfiguration = null)
{
var traceLog = new TraceLog(new EventPipeEventSource(session.EventStream));
traceLog.rawEventSourceToConvert.AllEvents += traceLog.OnAllEventPipeEventsRealTime;

if (rundownSession != null)
var rundownDiagnosticsClient = rundownConfiguration?.m_client;
if (rundownDiagnosticsClient != null)
{
traceLog.ProcessInitialRundown(rundownSession);
// Rundown events only come in after the session is stopped but we need them right from the start so that we
// can recognize loaded moodules and methods. Therefore, we start an additional session which will only collect
// rundown events and shut down immediately and feed this as an additional session to the TraceLog.
// Note: it doesn't matter what the actual provider is, just that we request rundown in the constructor.
using (var rundownSession = rundownDiagnosticsClient.StartEventPipeSession(
new EventPipeProvider(ClrTraceEventParser.ProviderName, EventLevel.Informational, (long)ClrTraceEventParser.Keywords.Default),
requestRundown: true
)) {
traceLog.ProcessInitialRundown(rundownSession);
}
}

return traceLog.realTimeSource;
}

public class EventPipeRundownConfiguration
{
internal readonly DiagnosticsClient m_client;

private EventPipeRundownConfiguration(DiagnosticsClient client) { m_client = client; }

public static EventPipeRundownConfiguration None()
{
return new EventPipeRundownConfiguration(null);
}

public static EventPipeRundownConfiguration Enable(DiagnosticsClient client)
{
return new EventPipeRundownConfiguration(client);
}
}

private void ProcessInitialRundown(EventPipeSession session)
{
using (var source = new EventPipeEventSource(session.EventStream))
Expand Down Expand Up @@ -255,54 +279,22 @@ private void SetupInitialRundownCallbacks(EventPipeEventSource rawEvents)
clrRundownParser.LoaderModuleDCStop += onLoaderRundown;
clrRundownParser.LoaderModuleDCStart += onLoaderRundown;

// TODO We don't seem to be getting any of these events, only MethodDCStopVerbose.
// clrRundownParser.MethodDCStartVerbose += delegate (MethodLoadUnloadVerboseTraceData data)
// {
// if (data.IsJitted)
// {
// TraceProcess process = processes.GetOrCreateProcess(data.ProcessID, data.TimeStampQPC);
// process.InsertJITTEDMethod(data.MethodStartAddress, data.MethodSize, delegate ()
// {
// TraceManagedModule module = process.LoadedModules.GetOrCreateManagedModule(data.ModuleID, data.TimeStampQPC);
// MethodIndex methodIndex = CodeAddresses.Methods.NewMethod(TraceLog.GetFullName(data), module.ModuleFile.ModuleFileIndex, data.MethodToken);
// return new TraceProcess.MethodLookupInfo(data.MethodStartAddress, data.MethodSize, methodIndex);
// });

// jittedMethods.Add((MethodLoadUnloadVerboseTraceData)data.Clone());
// }
// };

clrRundownParser.MethodILToNativeMapDCStop += delegate (MethodILToNativeMapTraceData data)
{
codeAddresses.AddILMapping(data);
};

clrRundownParser.MethodDCStopVerbose += delegate (MethodLoadUnloadVerboseTraceData data)
{
// TODO we need this also for non-jitted methods, otherwise we won't resolve some frames, for example:
// Note: we need this also for non-jitted methods, otherwise we won't resolve some frames, for example:
// "System.Private.CoreLib.il" - "System.Threading.Tasks.Task.Wait()"
// Is it OK to use InsertJITTEDMethod & FindJITTEDMethodFromAddress or do we need something else?
// if (data.IsJitted)
// {
TraceProcess process = processes.GetOrCreateProcess(data.ProcessID, data.TimeStampQPC);
process.InsertJITTEDMethod(data.MethodStartAddress, data.MethodSize, delegate ()
{
TraceManagedModule module = process.LoadedModules.GetOrCreateManagedModule(data.ModuleID, data.TimeStampQPC);
MethodIndex methodIndex = CodeAddresses.Methods.NewMethod(GetFullName(data), module.ModuleFile.ModuleFileIndex, data.MethodToken);
return new TraceProcess.MethodLookupInfo(data.MethodStartAddress, data.MethodSize, methodIndex);
});
// }
// if (data.IsJitted)
// {
// ILMapIndex ilMap = UnloadILMapForMethod(methodIndex, data);
// }
// // Set the info
// info.SetMethodIndex(this, methodIndex);
// if (ilMap != ILMapIndex.Invalid)
// {
// info.SetILMapIndex(this, ilMap);
// }
// info.SetOptimizationTier(data.OptimizationTier);
};
}

Expand Down