7
7
using FastSerialization ;
8
8
using Microsoft . Diagnostics . NETCore . Client ;
9
9
using Microsoft . Diagnostics . Symbols ;
10
- using Microsoft . Diagnostics . Tracing . Compatibility ;
11
10
using Microsoft . Diagnostics . Tracing . EventPipe ;
12
11
using Microsoft . Diagnostics . Tracing . Parsers ;
13
12
using Microsoft . Diagnostics . Tracing . Parsers . AspNet ;
@@ -155,6 +154,7 @@ public static TraceLog OpenOrConvert(string etlOrEtlxFilePath, TraceLogOptions o
155
154
public static TraceLogEventSource CreateFromTraceEventSession ( TraceEventSession session )
156
155
{
157
156
var traceLog = new TraceLog ( session . Source ) ;
157
+ traceLog . pointerSize = ETWTraceEventSource . GetOSPointerSize ( ) ;
158
158
159
159
// See if we are on Win7 and have a separate kernel session associated with 'session'
160
160
if ( session . m_kernelSession != null )
@@ -168,24 +168,32 @@ public static TraceLogEventSource CreateFromTraceEventSession(TraceEventSession
168
168
traceLog . rawKernelEventSource = session . m_kernelSession . Source ;
169
169
traceLog . SetupCallbacks ( traceLog . rawKernelEventSource ) ;
170
170
traceLog . rawKernelEventSource . unhandledEventTemplate . traceEventSource = traceLog ; // Make everything point to the log as its source.
171
- // TODO fixme - onAllEvents is local to the constructor
172
- // traceLog.rawKernelEventSource.AllEvents += traceLog.onAllEvents;
171
+ traceLog . rawKernelEventSource . AllEvents += traceLog . onAllEventsRealTime ;
173
172
}
174
173
175
174
return traceLog . realTimeSource ;
176
175
}
177
176
177
+ /// <summary>
178
+ /// From a EventPipeSession, create a real time TraceLog Event Source. Like an EventPipeEventSource a TraceLogEventSource
179
+ /// will deliver events in real time. However an TraceLogEventSource has an underlying Tracelog (which you can access with
180
+ /// the .Log Property) which lets you get at aggregated information (Processes, threads, images loaded, and perhaps most
181
+ /// importantly TraceEvent.CallStack() will work. Thus you can get real time stacks from events).
182
+ /// </summary>
178
183
public static TraceLogEventSource CreateFromEventPipeSession ( EventPipeSession session )
179
184
{
180
185
return CreateFromEventPipeEventSource ( new EventPipeEventSource ( session . EventStream ) ) ;
181
186
}
182
187
188
+ /// <summary>
189
+ /// From a EventPipeEventSource, create a real time TraceLog Event Source. Like an EventPipeEventSource a TraceLogEventSource
190
+ /// will deliver events in real time. However an TraceLogEventSource has an underlying Tracelog (which you can access with
191
+ /// the .Log Property) which lets you get at aggregated information (Processes, threads, images loaded, and perhaps most
192
+ /// importantly TraceEvent.CallStack() will work. Thus you can get real time stacks from events).
193
+ /// </summary>
183
194
public static TraceLogEventSource CreateFromEventPipeEventSource ( EventPipeEventSource source )
184
195
{
185
196
var traceLog = new TraceLog ( source ) ;
186
- var dynamicParser = source . Dynamic ;
187
- var clrParser = source . Clr ;
188
- var kernelParser = source . Kernel ;
189
197
return traceLog . realTimeSource ;
190
198
}
191
199
@@ -583,65 +591,63 @@ private unsafe TraceLog(TraceEventDispatcher source)
583
591
584
592
realTimeSource = new TraceLogEventSource ( events , ownsItsTraceLog : true ) ; // Dispose
585
593
realTimeQueue = new Queue < QueueEntry > ( ) ;
586
- realTimeFlushTimer = new Timer ( FlushRealTimeEvents , null , 1000 , 1000 ) ;
587
- pointerSize = ETWTraceEventSource . GetOSPointerSize ( ) ;
594
+ realTimeFlushTimer = new Timer ( _ => FlushRealTimeEvents ( 1000 ) , null , 1000 , 1000 ) ;
588
595
589
596
//double lastTime = 0;
590
597
591
- // Set up callbacks that handle stack processing
592
- Action < TraceEvent > onAllEvents = delegate ( TraceEvent data )
593
- {
594
- // we need to guard our data structures from concurrent access. TraceLog data
595
- // is modified by this code as well as code in FlushRealTimeEvents.
596
- lock ( realTimeQueue )
597
- {
598
- // we delay things so we have a chance to match up stacks.
599
-
600
- // if (!removeFromStream && data.Opcode != TraceEventOpcode.DataCollectionStart && data.ProcessID != 0 && data.ProviderGuid != ClrRundownTraceEventParser.ProviderGuid)
601
- // Trace.WriteLine("REAL TIME QUEUE: " + data.ToString());
602
- TraceEventCounts countForEvent = Stats . GetEventCounts ( data ) ;
603
- Debug . Assert ( ( int ) data . EventIndex == eventCount ) ;
604
- countForEvent . m_count ++ ;
605
- countForEvent . m_eventDataLenTotal += data . EventDataLength ;
598
+ // Set up callbacks - we use the session's source for our input.
599
+ rawEventSourceToConvert = source ;
600
+ SetupCallbacks ( rawEventSourceToConvert ) ;
601
+ rawEventSourceToConvert . unhandledEventTemplate . traceEventSource = this ; // Make everything point to the log as its source.
602
+ rawEventSourceToConvert . AllEvents += onAllEventsRealTime ;
603
+ }
606
604
607
- // Remember past events so we can hook up stacks to them.
608
- data . eventIndex = ( EventIndex ) eventCount ;
609
- pastEventInfo . LogEvent ( data , data . eventIndex , countForEvent ) ;
605
+ private unsafe void onAllEventsRealTime ( TraceEvent data )
606
+ {
607
+ // we need to guard our data structures from concurrent access. TraceLog data
608
+ // is modified by this code as well as code in FlushRealTimeEvents.
609
+ lock ( realTimeQueue )
610
+ {
611
+ // we delay things so we have a chance to match up stacks.
610
612
611
- // currentID is used by the dispatcher to define the EventIndex. Make sure at both sources have the
612
- // same notion of what that is if we have two dispatcher.
613
- if ( rawKernelEventSource != null )
614
- {
615
- rawEventSourceToConvert . currentID = ( EventIndex ) eventCount ;
616
- rawKernelEventSource . currentID = ( EventIndex ) eventCount ;
617
- }
613
+ // if (!removeFromStream && data.Opcode != TraceEventOpcode.DataCollectionStart && data.ProcessID != 0 && data.ProviderGuid != ClrRundownTraceEventParser.ProviderGuid)
614
+ // Trace.WriteLine("REAL TIME QUEUE: " + data.ToString());
615
+ TraceEventCounts countForEvent = Stats . GetEventCounts ( data ) ;
616
+ Debug . Assert ( ( int ) data . EventIndex == eventCount ) ;
617
+ countForEvent . m_count ++ ;
618
+ countForEvent . m_eventDataLenTotal += data . EventDataLength ;
618
619
619
- // Skip samples from the idle thread.
620
- if ( data . ProcessID == 0 && data is SampledProfileTraceData )
621
- {
622
- return ;
623
- }
620
+ // Remember past events so we can hook up stacks to them.
621
+ data . eventIndex = ( EventIndex ) eventCount ;
622
+ pastEventInfo . LogEvent ( data , data . eventIndex , countForEvent ) ;
624
623
625
- var extendedDataCount = data . eventRecord ->ExtendedDataCount ;
626
- if ( extendedDataCount != 0 )
627
- {
628
- bookKeepingEvent |= ProcessExtendedData ( data , extendedDataCount , countForEvent ) ;
629
- }
624
+ // currentID is used by the dispatcher to define the EventIndex. Make sure at both sources have the
625
+ // same notion of what that is if we have two dispatcher.
626
+ if ( rawKernelEventSource != null )
627
+ {
628
+ rawEventSourceToConvert . currentID = ( EventIndex ) eventCount ;
629
+ rawKernelEventSource . currentID = ( EventIndex ) eventCount ;
630
+ }
630
631
631
- // This must occur after the call to ProcessExtendedData to ensure that if there is a stack for this event,
632
- // that it has been associated before the event count is incremented. Otherwise, the stack will be associated with
633
- // the next event, and not the current event.
634
- eventCount ++ ;
632
+ // Skip samples from the idle thread.
633
+ if ( data . ProcessID == 0 && data is SampledProfileTraceData )
634
+ {
635
+ return ;
636
+ }
635
637
636
- realTimeQueue . Enqueue ( new QueueEntry ( data . Clone ( ) , Environment . TickCount ) ) ;
638
+ var extendedDataCount = data . eventRecord ->ExtendedDataCount ;
639
+ if ( extendedDataCount != 0 )
640
+ {
641
+ bookKeepingEvent |= ProcessExtendedData ( data , extendedDataCount , countForEvent ) ;
637
642
}
638
- } ;
639
643
640
- // We use the session's source for our input.
641
- rawEventSourceToConvert = source ;
642
- SetupCallbacks ( rawEventSourceToConvert ) ;
643
- rawEventSourceToConvert . unhandledEventTemplate . traceEventSource = this ; // Make everything point to the log as its source.
644
- rawEventSourceToConvert . AllEvents += onAllEvents ;
644
+ // This must occur after the call to ProcessExtendedData to ensure that if there is a stack for this event,
645
+ // that it has been associated before the event count is incremented. Otherwise, the stack will be associated with
646
+ // the next event, and not the current event.
647
+ eventCount ++ ;
648
+
649
+ realTimeQueue . Enqueue ( new QueueEntry ( data . Clone ( ) , Environment . TickCount ) ) ;
650
+ }
645
651
}
646
652
647
653
/// <summary>
@@ -672,25 +678,19 @@ private unsafe void DispatchClonedEvent(TraceEvent toSend)
672
678
}
673
679
674
680
/// <summary>
675
- /// Flushes any event that has waited around long enough
681
+ /// Flushes any event that has waited around for longer than minimumAgeMs.
676
682
/// </summary>
677
- private void FlushRealTimeEvents ( object notUsed )
683
+ internal void FlushRealTimeEvents ( int minimumAgeMs = 0 )
678
684
{
679
685
lock ( realTimeQueue )
680
686
{
681
687
var nowTicks = Environment . TickCount ;
682
688
// TODO review.
683
- for ( ; ; )
689
+ while ( realTimeQueue . Count > 0 )
684
690
{
685
- var count = realTimeQueue . Count ;
686
- if ( count == 0 )
687
- {
688
- break ;
689
- }
690
-
691
691
QueueEntry entry = realTimeQueue . Peek ( ) ;
692
692
// If it has been in the queue less than 1 second, we we wait until next time) & 3FFFFFF does wrap around subtraction.
693
- if ( ( ( nowTicks - entry . enqueueTick ) & 0x3FFFFFFF ) < 1000 )
693
+ if ( minimumAgeMs > 0 && ( ( nowTicks - entry . enqueueTick ) & 0x3FFFFFFF ) < minimumAgeMs )
694
694
{
695
695
break ;
696
696
}
@@ -4323,6 +4323,8 @@ public override bool Process()
4323
4323
TraceLog . rawKernelEventSource . StopProcessing ( ) ;
4324
4324
kernelTask . Wait ( ) ;
4325
4325
}
4326
+ // Flush all outstanding events in the realTimeQueue.
4327
+ TraceLog . FlushRealTimeEvents ( ) ;
4326
4328
return true ;
4327
4329
}
4328
4330
Debug . Assert ( unhandledEventTemplate . traceEventSource == TraceLog ) ;
0 commit comments