Microsoft.Diagnostics.Tracing.TraceEvent The base class for all analyzers. Called by the platform to execute the Analyzer. The context associated with this execution of the Analyzer. The result of the execution. Optional configuration information for an Analyzer. Add a key value pair. The unique key. The value. Attempt to fetch a configuration value using its unique key. The unique key. The value. True iff a configuration entry with the specified unique key was found. Attempt to fetch a configuration value using its unique key and convert it to a double. The unique key. The value. True iff a configuration entry with the specified unique key was found and could be converted to a double. The top-level object used to store contextual information during Analyzer execution. The configuration for the currently executing Analyzer. NULL if no configuration is available. The trace to be analyzed. Add an identified issue. The process associated with the issue. The issue. A result returned after execution of an Analyzer. An issue identified by an Analyzer. Create a new instance of AnalyzerIssue. A string title. A string description. A URL pointing to further documentation. Instances of AnalyzerIssue can only be created during Analyzer execution. The Analyzer that created the issue. The title of the issue. The description of the issue. A URL pointing to further documentation on the issue. A collection of AnalyzerIssue instances organized by process. Get a list of issues for the specified process. The process. A list of issues associated with the specified process. The context object used when loading an Analyzer. The Analyzer being loaded. True iff the Analyzer should be run during trace processing. The base class for all resolver implementations. Called when each Analyzer is loaded. The context for the Analyzer load. Searches the specified assembly for Analyzer instances and loads them. The assembly to consume. Called to discover assemblies that contain Analyzers to be executed. TextWriter implementation that allows TraceEvent constructions to log to EventSource along with other AutomatedAnalysis logging. Encapsulates a TraceEvent TraceLog within the AutomatedAnalysis system. Create a new instance for the specified TraceLog and SymbolReader. The TraceLog instance. A SymbolReader that can be used to resolve symbols within the TraceLog. The underlying source of the data. A report generator whose output format is HTML. Create a new instance of HtmlReportGenerator. The destination for the report. Write out the specified process information and issues. The process. The list of issues. Write out the set of executed analyzers. The set of executed analyzers. The assembly-level attribute used by Analyzer developers to identify the class that implements IAnalyzerProvider for the assembly. Create an new instance of AnalyzerProviderAttribute which stores the Type of the IAnalyzerProvider for the assembly. The type contained in this assembly that implements IAnalyzerProvider. The type that implements IAnalyzerProvider. The interface used within Analyzer assemblies to publish the set of Analyzers that are consumable from the assembly. Called to provide the list of Analyzers published by the assembly. A common set of supported stacks. Stacks representing execution on one or more CPUs. The common interface for all supported trace formats. The set of processes contained within the trace. Get a StackView containing stacks for the specified process and stack type. The process to filter stacks by. The type of stacks for the request. A StackView containing the requested stacks. A process contained in a trace. Create an instance with default values. Create an instance with the specified values. The unique id for the process. The display id for the process. The string description for the process. Whether or not the process contains any managed code. The unique ID of the process. The ID that should be used for display purposes. The description for the process. True iff the process contains managed code. An Analyzer that is invoked individually for each process in a trace. Called by the platform to analyze a single process. The context associated with this execution of the Analyzer. The process-specific context associated with this execution of the Analyzer. The result of the execution. The process-specific context associated with execution of ProcessAnalyzers. The process being analyzed. The CPU stacks for the process being analyzed. Add an identified issue. The issue. A view into a set of aggregated stacks. Create a new instance of StackView for the specified source. Optional: The TraceLog associated with the StackSource. The souce of the stack data. Optional: A symbol reader that can be used to lookup symbols. The call tree representing all stacks in the view. All nodes in the view ordered by exclusive metric. Find a node. The regex pattern for the node name. The requested node, or the root node if requested not found. Get the set of caller nodes for a specified symbol. The symbol. Get the set of callee nodes for a specified symbol. The symbol. Get the call tree node for the specified symbol. The symbol. The call tree node representing the symbol, or null if the symbol is not found. Unwind the wrapped sources to get to a TraceEventStackSource if possible. Processes traces by running a set of Analyzers against the trace data. Creates a new instance of TraceProcessor with the specified AnalyzerResolver. The resolver that will be used to discover Analyzers for execution. Process a single trace. The trace. The result of processing the trace. The result of a trace processing operation. The set of Analyzers that were executed. The set of issues identified by the executed Analyzers. delegate for decompress BPerf file. input byte array for decompress the offset of stream start position the length of input stream the output buffer byte array the length of output stream BPerf Trace Log (BTL) are files generated by the CPU Samples Collector tool in https://github.com/Microsoft/BPerf The layout of the file is as follows --> Format: 4 byte integer describing compressed size 4 byte integer describing uncompressed size byte[compressed size] The byte array is a list of EVENT_RECORDs. Each Event_RECORD is aligned to 16-bytes. The EVENT_RECORD is laid out as a memory dump of the structure in memory. All pointers from the structure are laid out successively in front of the EVENT_RECORD. The compression mechanism is using the LZ4 17-Bits Window, 3 Bit Run Length, 4 Bits Match Length. The delegate for decompress btl event file. This constructor is used when the consumer has an offset within the BTL file that it would like to seek to. This constructor is used when the consumer is supplying the buffers for reasons like buffer pooling. The delegate function to decompress by using ULZ777 algorithm An ActivityComputer is a state machine that track information about Activities. In particular, it can compute a activity aware call stack. (GetCallStack). Construct a new ActivityComputer that will process events from 'eventLog' and output activity - aware stacks to 'outputStackSource'. Returns the TraceLog that is associated with the computer (at construction time) Fires when an activity is first created (scheduled). The activity exists, and has an ID, but has not run yet. First when an activity starts to run (using a thread). It fires after the start has logically happened. so you are logically in the started activity. Fires when the activity ends (no longer using a thread). It fires just BEFORE the task actually dies (that is you ask the activity of the event being passed to 'Stop' it will still give the passed activity as the answer). The first TraceActivity is the activity that was stopped, the second is the activity that exists afer the stop completes. Like OnStop but gets called AFTER the stop has completed (thus the current thread's activity has been updated) The activity may be null, which indicates a failure to look up the activity being stopped (and thus the thread's activity will be set to null). AwaitUnblocks is a specialized form of the 'Start' event that fires when a task starts because an AWAIT has ended. The start event also fires on awaits end and comes AFTER the AwaitUnblocks event has been delivered. Not every AWAIT end causes a callback. Because an AWAIT begin happens for every FRAME you only want a callback for the FIRST task (activity) created by parent of this activity. This is what this callback does. AwaitUnblocks are often treated differently because you want to consider the time between the begin (Activity Created) and awaitUnbock to be accounted for as on the critical path, whereas for 'normal' tasks you normally don't think that time is interesting. Fetches the current activity for 'thread' at the present time (the current event being dispatched). Never returns null because there is always and activity (it may be the thread task). This is arguably the main thing that this computer keeps track of. Gets the default activity for a thread (the activity a thread is doing when the thread starts). Maps an activity index back to its activity. Returns a activity-aware call stackIndex associated with'ouputStackSource' for the call stack associated with 'data'. Such activity-aware call stacks have pseudo-frame every time on thread causes another task to run code (because the creator 'caused' the target code). If 'topFrames' is non-null, then this function is called with a Thread and is expected to return a CallStack index that represents the thread-and-process nodes of the stack. This allows the returned stack to be have pseudo-frames at the root of the stack. Typically this is used to represent the 'request' or other 'global' context. If it is not present the thread and process are used to form these nodes. This needs to be a function mapping threads to the stack base rather than just the stack base because in the presence of activities the thread at the 'base' whose 'top' you want may not be the one that 'data' started with, so the caller needs to be prepared to answer the question about any thread. Returns a StackSource call stack associated with outputStackSource for the activity 'activity' (that is the call stack at the the time this activity was first created. This stack will have it 'top' defined by topFrames (by default just the thread and process frames) This is not a call stack but rather the chain of ACTIVITIES (tasks), and can be formed even when call stacks Returns a Stack Source stack associated with outputStackSource where each frame is a task starting with 'activity' and going back until the activity has no parent (e.g. the Thread's default activity). If set, we don't assume that the top top frames are an attribute of the TOP THREAD (if they vary based on the current activity, then you can't cache. Setting this disables caching. Returns true if the call stack is in the thread pool parked (not running user code) This means that the thread CAN'T be running an active activity and we can kill it. This cache remembers Activity * CallStackIndex pairs and the result. Remembers the current Activity for 'Get' and 'Put' operations. Needs to be set before Get or Put is called. Gets the cache entry for the CurrnetActivityIndex with the call stack 'fromStackIndex' returns Invalid if there is no entry. This is not passed the CurrentActivityIndex, so it can implement the CallStackMap interface updates the cache entry for the CurrnetActivityIndex with the call stack 'fromStackIndex' with the value 'toStackIndex' This is not passed the CurrentActivityIndex, so it can implement the CallStackMap interface Creation handles ANY creation of a task. Activity can be null, which means we could not figure out the activity we are stopping. Get a trace wide ID for a TPL event. TPL tasks might be 'Scheduled' in the sense that it might run independently on another thread. Tasks that do 'BeginWait and 'EndWait' are not scheduled. The same ID might have both operating simultaneously (if you wait on a scheduled task). Thus you need an independent ID for both. if 'activity' has not creator (it is top-level), then return baseStack (near execution) followed by 'top' representing the thread-process frames. otherwise, find the fragment of 'baseStack' up to the point to enters the threadpool (the user code) and splice it to the stack of the creator of the activity and return that. (thus returning your full user-stack). Trims off frames that call ETW logic and return. If the pattern is not matched, we return callStackIndex If the stack from 'startStack' (closest to execution) through 'stopStack' is the same as 'baseStack' return a non-invalid frame indicating that it is recursive and should be dropped. The frame index returned is the name of the task on 'baseStack' that begins the recursion (so you can update it if necessary) Create a stack which is executing at 'startStack' and finds the region until 'stopStack', appending that (in order) to 'baseStack'. Returns the point in 'callStackIndex' where the CLR thread pool transitions from a thread pool worker to the work being done by the threadpool. Basically we find the closest to execution (furthest from thread-start) call to a 'Run' method that shows we are running an independent task. Used by TrimETWFrames and FindThreadPoolTransition to find particular frame names and place the information in 'm_methodFlags' We look for various well known methods inside the Task library. This array maps method indexes and returns a bitvector of 'kinds' of methods (Run, Schedule, ScheduleHelper). A small number that you can get from the GetReferenceForGCAddress that is invariant as the GC address moves around during GCs. Because this index is small it can be used to store information about the GC reference in a side growable array. Indicates that the address is no longer alive. This computer will keep track of GC references as they change over time Create a new GCRefernece computer from the stream of events 'source'. When 'source' is processed you can call 'GetReferenceForGCAddress' to get stable ids for GC references. Get a stable ID for a GcAddress. This ID can be compared for object identity. This only works at the current point in time when scanning the source. If you no longer need to track the GC reference, call this function to remove the tracking. A EventPipeThreadTimeComputer does a simple simulation of what each thread is doing to create stack events that represent CPU, blocked time Create a new ThreadTimeComputer If set we compute thread time using Tasks Track additional info on like EventName or so. Default to true to keep backward compatibility. Use start-stop activities as the grouping construct. Reduce nested application insights requests by using related activity id. Generate the thread time stacks, outputting to 'stackSource'. Optional filtered trace events. Updates it so that 'thread' is now working on newStartStop, which can be null which means that it is not working on any start-stop task. This can actually be called with any event that has a stack. Basically it will log a CPU sample whose size is the time between the last such call and the current one. Get the call stack for 'data' Note that you thread must be data.Thread(). We pass it just to save the lookup. Returns a function that figures out the top (closest to stack root) frames for an event. Often this returns null which means 'use the normal thread-process frames'. Normally this stack is for the current time, but if 'getAtCreationTime' is true, it will compute the stack at the time that the current activity was CREATED rather than the current time. This works better for await time. Represents all the information that we need to track for each thread. Used to create UNKNOWN frames for start-stop activities. This is indexed by StartStopActivityIndex. and for each start-stop activity indicates when unknown time starts. However if that activity still has known activities associated with it then the number will be negative, and its value is the ref-count of known activities (thus when it falls to 0, it we set it to the start of unknown time. This is indexed by the TOP-MOST start-stop activity. maps thread ID to the current TOP-MOST start-stop activity running on that thread. Used to updated m_unknownTimeStartMsec to figure out when to put in UNKNOWN_ASYNC nodes. Sadly, with AWAIT nodes might come into existence AFTER we would have normally identified a region as having no thread/await working on it. Thus you have to be able to 'undo' ASYNC_UNKONWN nodes. We solve this by remembering all of our ASYNC_UNKNOWN nodes on a list (basically provisional) and only add them when the start-stop activity dies (when we know there can't be another AWAIT. Note that we only care about TOP-MOST activities. Calculates stacks grouping them by the server request (e.g. ASP.NET) request they are for) Create a new ServerRequest Computer. The server request that we currently processing A ServerRequest contains all the information we know about a server request (e.g. ASP.NET request) Any URL associated with the request If the request has a GUID associated with it to uniquely identify it, this is it The time that the request started (or the earliest that we know about it) Calculates start-stop activities (computes duration), It uses the 'standard' mechanism of using ActivityIDs to corelate the start and stop (and any other events between the start and stop, and use the RelatedActivityID on START events to indicate the creator of the activity, so you can form nested start-stop activities. Create a new ServerRequest Computer. The current start-stop activity on the given thread. If present 'context' is used to look up the current activityID and try to use that to repair missing Starts. Basically if we can't figure out what StartStop activity the thread from just the threadID we can use the activityID from the 'context' event to find it as a backup. Gets the current Start-Stop activity for a given TraceActivity. Returns a stack index representing the nesting of Start-Stop activities for the thread 'curThread' at the current time (At this point of the current event for the computer). The stack starts with a frame for the process of the thread, then has all the start-stop activity frames, then a frame representing 'topThread' which may not be the same as 'thread' since 'topThread' is the thread that spawned the first task, not the currently executing thread. Normally this stack is for the current time, but if 'getAtCreationTime' is true, it will compute the stack at the time that the current activity was CREATED rather than the current time. This works better for await time Gets a stack that represents the nesting of the Start-Stop tasks. curActivity can be null, in which case just he process node is returned. If set, called AFTER a Start-Stop activity starts, called with the activity and the event that caused the start. If set, called BEFORE a Start-Stop activity stops, called with the activity and the event that caused the start. Returns true if 'guid' follow the EventSouce style activity ID for the process with ID processID. You can pass a process ID of 0 to this routine and it will do the best it can, but the possibility of error is significantly higher (but still under .1%) Assuming guid is an Activity Path, extract the process ID from it. returns a string representation for the activity path. If the GUID is not an activity path then it returns the normal string representation for a GUID. 0001111d-0000-0000-0000-00007bc7be59 will pass IsActivityPath check only when process Id 2125233 is provided. We don't do a stop all processing associated with the stop event is done. Thus if we are not 'on' the stop event, then you can do any deferred processing. Try to process some predefined DiagnosticSource ("Microsoft.EntityFrameworkCore.BeforeExecuteCommand" and "Microsoft.AspNetCore.Hosting.BeginRequest") start events. This will try to filter the events by "EventName", if failed it will return false without any further processing. Whether or not succeeded in processing the event fix ASP.NET receiving events Look up a start-stop activity by its ID. Note that the 'activityID' needs to be unique for that instance within a process. (across ALL start-stop activities, which means it may need components that encode its provider and task). We pass the process ID as well so that it will be unique in the whole trace. The encoding for a list of numbers used to make Activity Guids. Basically we operate on nibbles (which are nice because they show up as hex digits). The list is ended with a end nibble (0) and depending on the nibble value (Below) the value is either encoded into nibble itself or it can spill over into the bytes that follow. An dense number that defines the identity of a StartStopActivity. Used to create side arrays for StartStopActivity info. An illegal index, sutable for a sentinal. A StartStop reresents an activity between a start and stop event as generated by EvetSource. The index (small dense numbers suitabilty for array indexing) for this activity. The name of the activity (The Task name for the start-stop event as well as the activity ID) Known Activity Type If the activity has additional information associated with it (e.g. a URL), put it here. Can be null. The Task name (the name prefix that is common to both the start and stop event) The processID associated with this activity The Activity ID (as a GUID) that matches the start and stop together. The path of creators that created this activity. The start-stop activity that created this activity (thus it makes a tree) The TraceLog event Index, of the start event (you can get addition info) The TraceLog event Index, of the stop event (you can get addition info) The time in MSec from the start of the trace when the start event happened. The duration of activity in MSec (diff between stop and start) This activity has completed (the Stop event has been received). Thus Duration is valid. Returns a stack on the outputStackSource which has a frame for each activity that caused this activity, as well as the root of the given 'rootStack' (often a stack representing the process). override. Gives the name and start time. We don't update the state for the stop at the time of the stop, but at the next call to any of the StartStopActivityComputer APIs. A TcpIpComputer keeps track of TCP/IP connections so that you can correlate individual reads and writes with the connection info (like the IP address of each end), as well as data packets being sent (if you have packet capture turned on). Create a new GCRefernece computer from the stream of events 'source'. When 'source' is processed you can call 'GetReferenceForGCAddress' to get stable ids for GC references. A ThreadTimeComputer does a simple simulation of what each thread is doing to create stack events that represent CPU, blocked time, disk and Network activity. Create a new ThreadTimeComputer If set we compute thread time using Tasks Track additional info on like EventName or so. Default to true to keep backward compatibility. If set we compute blocked time If set we don't show ready thread information If set we group by ASP.NET Request If we spend less then this amount of time waiting for the CPU, don't bother showing it. LIke the GroupByAspNetRequest but use start-stop activities instead of ASP.NET Requests as the grouping construct. Reduce nested application insights requests by using related activity id. Don't show AwaitTime. For CPU only traces showing await time is misleading since blocked time will not show up. Generate the thread time stacks, outputting to 'stackSource'. Optional filtered trace events. Updates it so that 'thread' is now working on newStartStop, which can be null which means that it is not working on any start-stop task. This can actually be called with any event that has a stack. Basically it will log a CPU sample whose size is the time between the last such call and the current one. Get the call stack for 'data' Note that you thread must be data.Thread(). We pass it just to save the lookup. Returns a function that figures out the top (closest to stack root) frames for an event. Often this returns null which means 'use the normal thread-process frames'. Normally this stack is for the current time, but if 'getAtCreationTime' is true, it will compute the stack at the time that the current activity was CREATED rather than the current time. This works better for await time. Represents all the information that we need to track for each thread. Given and activity, return the ASP.NET Guid associated with it (or Guid.Empty if there is not one). Computes the ASP.NET Pseudo frames from the process frame through the thread frame (which includes all the pseudo-frames for the ASP.NET groupings. Indicates that the aspNet request represented by aspNetGuid is now being handled by the thread with index newThreadIndex. Thus any old threads handling this request are 'cleared' and replaced with 'newThreadIndex' If 'newThreadIndex == Invalid then the entry for aspNetGuid is removed. Generate a stack that from the root looks like 'stackIndex followed by 'READIED BY TID(XXXX)' followed by frames of 'readyThreadCallStack' (suffixed by READIED_BY) NetworkInfo remembers useful information to tag blocked time that seems to be network related. It is the value of the m_lastPacketForProcess table mapping threads to network information. AspNetRequestInfo remembers everything we care about associate with an single ASP.NET request. It is the value of the m_aspNetRequestInfo table. Used to create UNKNOWN frames for start-stop activities. This is indexed by StartStopActivityIndex. and for each start-stop activity indicates when unknown time starts. However if that activity still has known activities associated with it then the number will be negative, and its value is the ref-count of known activities (thus when it falls to 0, it we set it to the start of unknown time. This is indexed by the TOP-MOST start-stop activity. maps thread ID to the current TOP-MOST start-stop activity running on that thread. Used to updated m_unknownTimeStartMsec to figure out when to put in UNKNOWN_ASYNC nodes. Sadly, with AWAIT nodes might come into existence AFTER we would have normally identified a region as having no thread/await working on it. Thus you have to be able to 'undo' ASYNC_UNKONWN nodes. We solve this by remembering all of our ASYNC_UNKNOWN nodes on a list (basically provisional) and only add them when the start-stop activity dies (when we know there can't be another AWAIT. Note that we only care about TOP-MOST activities. m_IRPToThread maps the I/O request to the thread that initiated it. This way we can associate the disk read size and file with the thread that asked for it. Maps processor number to the OS threadID of the thread that is using it. Allows you to determine how (CPU) idle the machine is. Using m_threadIDUsingProc, we compute how many processor are current doing nothing Returns the TraceLog that is associated with the computer (at construction time) Extension methods to enable TraceManagedProcess Extension properties for TraceProcess that include necessary .NET values TODO This implementation is poor at idenitfying the ParentPID, 64bitness, and Start/End times Returns the textual version of the .NET Framework Returns the .NET startup flags Date and time of when the runtime was built This is useful when a more detailed version is not present Garbage Collector (GC) specific details about this process Fired on the start of a GC Fired at the end of the GC. Given the nature of the GC, it is possible that multiple GCs will be inflight at the same time. Just-in-time compilation (JIT) specific details about this process Fired when a managed method is starting to compile (jit) Fired when a managed method is done compiling (jitting). Given the nature of the JIT, it is possible that multiple methods will be compiled at the same time. Indicates whether any of the jitted method code versions have a known optimization tier Indicates whether tiered compilation is enabled An XML representation of the TraceEventProcess (for debugging) Gathers relevant details about the processes in the event source Garbage Collector (GC) specific details about this process Process view of GC statistics Process view of GC generational statistics Process view of all GCs Just-in-time compilation (JIT) specific details about this process Process view of JIT statistics Process view of all methods jitted Primary GC information Type of the GC, eg. NonConcurrent, Background or Foreground Reason for the GC, eg. exhausted small heap, etc. Generation of the heap collected. If you compare Generation at the start and stop GC events they may differ. Time relative to the start of the trace. Useful for ordering Duration of the GC, excluding the suspension time Duration the EE suspended the process Time the EE took to suspend all the threads Percentage time the GC took compared to the process lifetime The number of CPU samples gathered for the lifetime of this process The number of CPU samples gathered during a GC Mark time information per heap. Key is the heap number Time since the last EE restart Realtive time to the trace of when the GC pause began Marks if the GC is in a completed state Server GC histories Amount of memory allocated since last GC. Requires GCAllocationTicks enabled. The data is split into small and large heaps Number of heaps. -1 is the default Calculate the size of all pinned objects Percentage of the pinned objects created by the user Total time taken by the GC Friendly GC name including type, reason and generation Heap size after GC (mb) Amount of memory promoted with GC (mb) Memory survival percentage by generation Heap size by generation after GC (mb) Heap fragmentation by generation (mb) Percentage of heap fragmented by generation Amount of memory at the start of the GC by generation (mb) Amount of memory after the gc by generation (mb) Memory promoted by generation (mb) Note that in 4.0 TotalPromotedSize is not entirely accurate (since it doesn't count the pins that got demoted. We could consider using the PerHeap event data to compute the accurate promoted size. In 4.5 this is accurate. Heap budget by generation (mb) Object size by generation after GC (mb) Global condemned reasons by GC Heap condemned reasons by GC Identify the first and greatest condemned heap Indicates that the GC has low ephemeral space Indicates that the GC was not compacting Returns the condemned reason for this heap Per heap statistics Sum of the pinned plug sizes Sum of the user created pinned plug sizes Per heap statstics Large object heap wait threads Process heap statistics Free list efficiency statistics Memory allocated since last GC (mb) Ratio of heap size before and after Ratio of allocations since last GC over time executed Peak heap size before GCs (mb) Per generation view of user allocated data Heap size before gc (mb) Per generation view of heap sizes before GC (mb) This represents the percentage time spent paused for this GC since the last GC completed. Get what's allocated into gen0 or gen3. For server GC this gets the total for all heaps. For a given heap, get what's allocated into gen0 or gen3. We calculate this differently on 4.0, 4.5 Beta and 4.5 RC+. The caveat with 4.0 and 4.5 Beta is that when survival rate is 0, We don't know how to calculate the allocated - so we just use the last GC's budget (We should indicate this in the tool) Legacy properties that need to be refactored and removed Condemned reasons are organized into the following groups. Each group corresponds to one or more reasons. Groups are organized in the way that they mean something to users. Background GC allocation information Span of thread work recorded by CSwitch or CPU Sample Profile events Reason for an induced GC CondemnedReason Heap condemned reason This records which reasons are used and the value. Since the biggest value we need to record is the generation number a byte is sufficient. Container for mark times Per heap statistics HasAllocatedInfo indicates the following fields will not be -1 FreeListAllocated FreeListRejected EndOfSegAllocated CondemnedAllocated PinnedAllocated PinnedAllocatedAdvance RunningFreeListEfficiency Process heap statistics Per heap stastics Approximations we do in this function for V4_5 and prior: On 4.0 we didn't separate free list from free obj, so we just use fragmentation (which is the sum) as an approximation. This makes the efficiency value a bit larger than it actually is. We don't actually update in for the older gen - this means we only know the out for the younger gen which isn't necessarily all allocated into the older gen. So we could see cases where the out is > 0, yet the older gen's free list doesn't change. Using the younger gen's out as an approximation makes the efficiency value larger than it actually is. For V4_6 this requires no approximation. Statistical garbage collector (GC) information about a managed process Number of GC's for this process Number of GC's which were induced, eg. GC.Collect, etc. Total size of the pinned objects seen at collection time Of all the memory that is current pinned, how much of it is from pinned objects Number of GC's that contained pinned objects Number of GC's that contained pin plugs The longest pause duration (ms) Avarege pause duration (ms) Average heap size after a GC (mb) Average peak heap size (mb) Average exclusive cpu samples (ms) during GC's Total GC pause time (ms) Max suspend duration (ms), should be very small Max peak heap size (mb) Max allocation per second (mb/sec) Total allocations in the process lifetime (mb) Total exclusive cpu samples (ms) Total memory promoted between generations (mb) (obsolete) Total size of heaps after GC'ss (mb) (obsolete) Total peak heap sizes (mb) Indication if this process is interesting from a GC pov List of finalizer objects Percentage of time spent paused as compared to the process lifetime Running time of the process. Measured as time spent between first and last GC event observed Means it detected that the ETW information is in a format it does not understand. Indicator of if ServerGC is enabled (1). -1 indicates that not enough events have been processed to know for sure. We don't necessarily have the GCSettings event (only fired at the beginning if we attach) So we have to detect whether we are running server GC or not. Till we get our first GlobalHeapHistory event which indicates whether we use server GC or not this remains -1. Number of heaps. -1 indicates that not enough events have been processed to know for sure. Indicator if PerHeapHistories is present Process statistics about JIT'd code Number of JITT'd methods Total cpu samples for this process Number of methods JITT'd by foreground threads just prior to execution Total time spent compiling methods on foreground threads Number of methods JITT'd by the multicore JIT background threads Total time spent compiling methods on background threads for multicore JIT Number of methods JITT'd by the tiered compilation background threads Total time spent compiling methods on background threads for tiered compilation Total IL size for all JITT'd methods Total native code size for all JITT'd methods Total hot code size allocated for all JITT'd methods Total read-only data size allocated for all JITT'd methods Total size allocated for all JITT'd methods If data from alloc size for JIT event present Indication if this is running on .NET 4.x+ Indicates if this process has sufficient JIT activity to be interesting Background JIT: Time Jit was aborted (ms) Background JIT: Assembly name of last assembly loaded before JIT aborted Background JIT: Relative start time of last assembly loaded before JIT aborted Background JIT: Indication if the last assembly load was successful before JIT aborted Background JIT: Thread id of the background JIT Background JIT: Indication that background JIT events are enabled Indicates whether any of the jitted method code versions in this process have a known optimization tier List of successfully inlinded methods List of failed inlined methods Modules encountered while processing managed samples List of modules whose symbols were not successfully loaded Aggregate a method to be included in the statistics Legacy Handles AllocRequest event for JIT Uniquely represents a method within a process. Used as a lookup key for data structures. JIT inlining successes JIT inlining failures Per method information Time taken to compile the method IL size of method Native code size of method Hot code size allocated for JIT code of method Read-only data size allocated for JIT code of method Total size allocated for JIT code of method Jit allocation flag Relative start time of JIT'd method Method name Module name Thread id where JIT'd Indication of if it was JIT'd in the background Indication of if it was JIT'd in the background and why Amount of time the method was forcasted to JIT Indication of if the background JIT request was blocked and why Number of cpu samples for this method The optimization tier at which the method was jitted The version id that is created by the runtime code versioning feature. This is an incrementing counter that starts at 0 for each method. The ETW events historically name this as the ReJITID event parameter in the payload, but we have now co-opted its usage. Legacy TraceProcess Extension methods Each process is given a unique index from 0 to TraceProcesses.Count-1 and unlike the OS Process ID, is unambiguous (The OS process ID can be reused after a process dies). ProcessIndex represents this index. By using an enum rather than an int it allows stronger typing and reduces the potential for errors. It is expected that users of this library might keep arrays of size TraceProcesses.Count to store additional data associated with a process in the trace. Returned when no appropriate Process exists. A TraceProcesses instance represents the list of processes in the Event log. TraceProcesses are IEnumerable, and will return the processes in order of creation time. This is a copy of the reduced code from TraceLog!TraceProcesses (removal of elements that depend on TraceLog - there is a lot of them) The log associated with this collection of processes. The count of the number of TraceProcess instances in the TraceProcesses list. Each process that occurs in the log is given a unique index (which unlike the PID is unique), that ranges from 0 to Count - 1. Return the TraceProcess for the given index. An XML representation of the TraceEventProcesses (for debugging) Enumerate all the processes that occurred in the trace log, ordered by creation time. Given an OS process ID and a time, return the last TraceProcess that has the same process ID, and whose offset start time is less than 'timeQPC'. If 'timeQPC' is during the thread's lifetime this is guaranteed to be the correct process. Using timeQPC = TraceLog.sessionEndTimeQPC will return the last process with the given PID, even if it had died. TraceProcesses represents the entire ETL moduleFile log. At the node level it is organized by threads. The TraceProcesses also is where we put various caches that are independent of the process involved. These include a cache for TraceModuleFile that represent native images that can be loaded into a process, as well as the process lookup tables and a cache that remembers the last calls to GetNameForAddress(). A step towards a refactored TraceProcess that will move down the dependcy chain from TraceLog to Source. This is only the portion of TraceProcess that is needed for ManagedProcess to exist. Also note, that the surface area is intended to match 100% with Microsoft.Diagnostics.Tracing.Etlx.TraceProcess. The namespace change is intention to avoid collision of the name and to indicate that it is moving down the depdnency chain. This is a slightly modified copy of the code from TraceLog!TraceProcess The OS process ID associated with the process. It is NOT unique across the whole log. Use ProcessIndex for that. The index into the logical array of TraceProcesses for this process. Unlike ProcessID (which may be reused after the process dies, the process index is unique in the log. This is a short name for the process. It is the image file name without the path or suffix. The command line that started the process (may be empty string if unknown) The path name of the EXE that started the process (may be empty string if unknown) The time when the process started. Returns the time the trace started if the process existed when the trace started. The time when the process started. Returns the time the trace started if the process existed when the trace started. Returned as the number of MSec from the beginning of the trace. The time when the process ended. Returns the time the trace ended if the process existed when the trace ended. Returned as a DateTime The time when the process ended. Returns the time the trace ended if the process existed when the trace ended. Returned as the number of MSec from the beginning of the trace. The process ID of the parent process The process that started this process. Returns null if unknown. If the process exited, the exit status of the process. Otherwise null. The amount of CPU time spent in this process based on the kernel CPU sampling events. Returns true if the process is a 64 bit process The log file associated with the process. Peak working set Peak virtual size A list of all the threads that occurred in this process. Returns the list of modules that were loaded by the process. The modules may be managed or native, and include native modules that were loaded event before the trace started. Filters events to only those for a particular process. Filters events to only that occurred during the time the process was alive. An XML representation of the TraceEventProcess (for debugging) Dummy stubs so Microsoft.Diagnostics.Tracing.Etlx namespace is not necessary The parsed metadata. Information about the trace itself. Information about a single stream in the trace. The environment the trace was taken in. A clock definition in the trace. A definition of an event. A manual parser for CtfMetadata. Eventually this should be replaced when CtfMetadata no longer uses a custom, BNF style format. The abstract metadata parser class. The types that may be declared in CtfMetatdata. This class represents the top level entry A simple class to make parsing out properties easier. Represents a type which has been referenced by name, but has not yet been resolved to a concrete type. A DynamicTraceEventParser is a parser that understands how to read the embedded manifests that occur in the dataStream (System.Diagnostics.Tracing.EventSources do this). See also TDHDynamicTraceEventParser which knows how to read the manifest that are registered globally with the machine. The event ID for the EventSource manifest emission event. Create a new DynamicTraceEventParser (which can parse ETW providers that dump their manifests to the ETW data stream) an attach it to the ETW data stream 'source'. Returns a list of providers (their manifest) that this TraceParser knows about. Given a manifest describing the provider add its information to the parser. Utility method that stores all the manifests known to the DynamicTraceEventParser to the directory 'directoryPath' Utility method that read all the manifests the directory 'directoryPath' into the parser. Manifests must end in a .man or .manifest.xml suffix. It will throw an error if the manifest is incorrect or using unsupported options. Override. This event, will be fired any time a new Provider is added to the table of ETW providers known to this DynamicTraceEventParser. This includes when the EventSource manifest events are encountered as well as any explicit calls to AddDynamicProvider. (including ReadAllManifests). The Parser will filter out duplicate manifest events, however if an old version of a provider's manifest is encountered, and later a newer version is encountered, you can receive this event more than once for a single provider. override Called on unhandled events to look for manifests. Returns true if we added a new manifest (which may have updated the lookup table) Override DynamicTraceEventData is an event that knows how to take runtime information to parse event fields (and payload) This meta-data is distilled down to a array of field names and an array of PayloadFetches which contain enough information to find the field data in the payload blob. This meta-data is used in the DynamicTraceEventData.PayloadNames and DynamicTraceEventData.PayloadValue methods. Implements TraceEvent interface Implements TraceEvent interface Implements TraceEvent interface Used by PayloadValue to represent a structure. It is basically a IDictionary with a ToString() that returns the value as JSON. Uses C style conventions to quote a string 'value' and append to the string builder 'sb'. Thus all \ are turned into \\ and all " into \" Implements TraceEvent interface Implements TraceEvent interface Returns the count of elements for the array represented by 'arrayInfo' It also will adjust 'offset' so that it points at the beginning of the array data (skips past the count). Constructor for normal types, (int, string) ...) Also handles Enums (which are ints with a map) Initialized a PayloadFetch for a given inType. REturns Size = DynamicTraceEventData.UNKNOWN_SIZE if the type is unknown. Returns a payload fetch for a Array. If you know the count, then you can give it. Offset from the beginning of the struct. LazyMap allow out to set a function that returns a map instead of the map itself. This will be evaluated when the map is fetched (which gives time for the map table to be populated. This class is only used to pretty-print the manifest event itself. It is pretty special purpose DynamicTraceEventParserState represents the state of a DynamicTraceEventParser that needs to be serialized to a log file. It does NOT include information about what events are chosen but DOES contain any other necessary information that came from the ETL data file. A ProviderManifest represents the XML manifest associated with the provider. Read a ProviderManifest from a stream Read a ProviderManifest from a file. Normally ProviderManifest will fail silently if there is a problem with the manifest. If you want to see this error you can all this method to force it explicitly It will throw if there is a problem parsing the manifest. Writes the manifest to 'outputStream' (as UTF8 XML text) Writes the manifest to a file 'filePath' (as a UTF8 XML) Set if this manifest came from the ETL data stream file. The name of the ETW provider The GUID that uniquey identifies the ETW provider The version is defined as the sum of all the version numbers of event version numbers + the number of events defined. This has the property that if you follow correct versioning protocol (all versions for a linear sequence where a new versions is only modifies is predecessor by adding new events or INCREASING the version numbers of existing events) then the version number defined below will always strictly increase. It turns out that .NET Core removed some events from the TplEtwProvider. To allow removal of truly old events we also add 100* the largest event ID defined to the version number. That way if you add new events, even if you removes some (less than 100) it will consider your 'better'. This is an arbitrary id given when the Manifest is created that identifies where the manifest came from (e.g. a file name or an event etc). Returns true if the current manifest is better to use than 'otherManifest' A manifest is better if it has a larger version number OR, they have the same version number and it is physically larger (we assume what happened is people added more properties but did not update the version field appropriately). Retrieve manifest as one big string. Mostly for debugging Retrieve the manifest as XML For debugging Call 'callback the the parsed templates for this provider. If 'callback' returns RejectProvider, bail early Note that the DynamicTraceEventData passed to the delegate needs to be cloned if you use subscribe to it. Returns the .NET type corresponding to the manifest type 'manifestTypeName' Returns null if it could not be found. Initialize the provider. This means to advance the instance variable 'reader' until it it is at the 'provider' node in the XML. It also has the side effect of setting the name and guid. The rest waits until events are registered. Keywords are passed to TraceEventSession.EnableProvider to enable particular sets of Logging when garbage collections and finalization happen. Events when GC handles are set or destroyed. Logging when modules actually get loaded and unloaded. Logging when Just in time (JIT) compilation occurs. Logging when precompiled native (NGEN) images are loaded. Indicates that on attach or module load , a rundown of all existing methods should be done Indicates that on detach or process shutdown, a rundown of all existing methods should be done Events associated with validating security restrictions. Events for logging resource consumption on an app-domain level granularity Logging of the internal workings of the Just In Time compiler. This is fairly verbose. It details decisions about interesting optimization (like inlining and tail call) Log information about code thunks that transition between managed and unmanaged code. Log when lock contention occurs. (Monitor.Enters actually blocks) Log exception processing. Log events associated with the threadpool, and other threading events. Dump the native to IL mapping of any method that is JIT compiled. (V4.5 runtimes and above). If enabled will suppress the rundown of NGEN events on V4.0 runtime (has no effect on Pre-V4.0 runtimes). Enables the 'BulkType' event Enables the events associated with dumping the GC heap Enables allocation sampling with the 'fast'. Sample to limit to 100 allocations per second per type. This is good for most detailed performance investigations. Note that this DOES update the allocation path to be slower and only works if the process start with this on. Enables events associate with object movement or survival with each GC. Triggers a GC. Can pass a 64 bit value that will be logged with the GC Start event so you know which GC you actually triggered. Indicates that you want type names looked up and put into the events (not just meta-data tokens). Enables allocation sampling with the 'slow' rate, Sample to limit to 5 allocations per second per type. This is reasonable for monitoring. Note that this DOES update the allocation path to be slower and only works if the process start with this on. Turns on capturing the stack and type of object allocation made by the .NET Runtime. This is only supported after V4.5.3 (Late 2014) This can be very verbose and you should seriously using GCSampledObjectAllocationHigh instead (and GCSampledObjectAllocationLow for production scenarios). This suppresses NGEN events on V4.0 (where you have NGEN PDBs), but not on V2.0 (which does not know about this bit and also does not have NGEN PDBS). TODO document Also log the stack trace of events for which this is valuable. This allows tracing work item transfer events (thread pool enqueue/dequeue/ioenqueue/iodequeue/a.o.) .NET Debugger events Events intended for monitoring on an ongoing basis. Events that will dump PDBs of dynamically generated assemblies to the ETW stream. Events that provide information about compilation. Diagnostic events for diagnosing compilation and pre-compilation features. Diagnostic events for capturing token information for events that express MethodID Diagnostic events for diagnosing issues involving the type loader. Recommend default flags (good compromise on verbosity). What is needed to get symbols for JIT compiled code. This provides the flags commonly needed to take a heap .NET Heap snapshot with ETW. Fetch the state object associated with this parser and cast it to the ClrTraceEventParserState type. This state object contains any information that you need from one event to another to decode events. (typically ID->Name tables). Note that this field is derived from the TotalPromotedSize* fields. If nothing was promoted, it is possible that this could give a number that is smaller than what GC/Start or GC/Stop would indicate. Returns the edge at the given zero-based index (index less than Count). The returned BulkTypeValues points the the data in GCBulkRootEdgeTraceData so it cannot live beyond that lifetime. This structure just POINTS at the data in the BulkTypeTraceData. It can only be used as long as the BulkTypeTraceData is alive which (unless you cloned it) is only for the lifetime of the callback. On the desktop this is the Method Table Pointer In project N this is the pointer to the EE Type For Desktop this is the Module* For project N it is image base for the module that the type lives in? On desktop this is the Meta-data token? On project N it is the RVA of the typeID Note that this method returns the type name with generic parameters in .NET Runtime syntax e.g. System.WeakReference`1[System.Diagnostics.Tracing.EtwSession] Returns the edge at the given zero-based index (index less than Count). The returned GCBulkRootEdgeValues points the the data in GCBulkRootEdgeTraceData so it cannot live beyond that lifetime. This structure just POINTS at the data in the GCBulkEdgeTraceData. It can only be used as long as the GCBulkEdgeTraceData is alive which (unless you cloned it) is only for the lifetime of the callback. Returns the range at the given zero-based index (index less than Count). The returned GCBulkRootConditionalWeakTableElementEdgeValues points the the data in GCBulkRootConditionalWeakTableElementEdgeTraceData so it cannot live beyond that lifetime. This structure just POINTS at the data in the GCBulkRootConditionalWeakTableElementEdgeTraceData. It can only be used as long as the GCBulkRootConditionalWeakTableElementEdgeTraceData is alive which (unless you cloned it) is only for the lifetime of the callback. Returns the node at the given zero-based index (idx less than Count). The returned GCBulkNodeNodes points the the data in GCBulkNodeTraceData so it cannot live beyond that lifetime. This unsafe interface may go away. Use the 'Nodes(idx)' instead This structure just POINTS at the data in the GCBulkNodeTraceData. It can only be used as long as the GCBulkNodeTraceData is alive which (unless you cloned it) is only for the lifetime of the callback. Returns the 'idx' th edge. The returned GCBulkEdgeEdges cannot live beyond the TraceEvent that it comes from. This structure just POINTS at the data in the GCBulkNodeTraceData. It can only be used as long as the GCBulkNodeTraceData is alive which (unless you cloned it) is only for the lifetime of the callback. Returns the range at the given zero-based index (index less than Count). The returned GCBulkSurvivingObjectRangesValues points the the data in GCBulkSurvivingObjectRangesTraceData so it cannot live beyond that lifetime. This structure just POINTS at the data in the GCBulkEdgeTraceData. It can only be used as long as the GCBulkEdgeTraceData is alive which (unless you cloned it) is only for the lifetime of the callback. Returns the range at the given zero-based index (index less than Count). The returned GCBulkSurvivingObjectRangesValues points the the data in GCBulkSurvivingObjectRangesTraceData so it cannot live beyond that lifetime. This structure just POINTS at the data in the GCBulkEdgeTraceData. It can only be used as long as the GCBulkEdgeTraceData is alive which (unless you cloned it) is only for the lifetime of the callback. We keep Heap history for every Generation in 'Gens' Taken from gcrecords.h, used to differentiate heap expansion and compaction reasons Version 0, PreciseVersion 0.1: Silverlight (x86) 0:041> dt -r2 coreclr!WKS::gc_history_per_heap +0x000 gen_data : [5] WKS::gc_generation_data +0x000 size_before : Uint4B/8B : [0 - 40), [40 - 80), [80 - 120), [120 - 160), [160 - 200) +0x004 size_after : Uint4B/8B +0x008 current_size : Uint4B/8B +0x00c previous_size : Uint4B/8B +0x010 fragmentation : Uint4B/8B +0x014 in : Uint4B/8B +0x018 out : Uint4B/8B +0x01c new_allocation : Uint4B/8B +0x020 surv : Uint4B/8B +0x024 growth : Uint4B/8B +0x0c8 mem_pressure : Uint4B : 200 +0x0cc mechanisms : [2] Uint4B : 204 (expand), 208 (compact) +0x0d4 gen_condemn_reasons : Uint4B : 212 +0x0d8 heap_index : Uint4B : 216 clrInstanceId : byte : 220 Version 0, PreciseVersion 0.2: .NET 4.0 0:000> dt -r2 clr!WKS::gc_history_per_heap +0x000 gen_data : [5] WKS::gc_generation_data +0x000 size_before : Uint4B/8B : [0 - 40), [40 - 80), [80 - 120), [120 - 160), [160 - 200) +0x004 size_after : Uint4B/8B +0x008 current_size : Uint4B/8B +0x00c previous_size : Uint4B/8B +0x010 fragmentation : Uint4B/8B +0x014 in : Uint4B/8B +0x018 out : Uint4B/8B +0x01c new_allocation : Uint4B/8B +0x020 surv : Uint4B/8B +0x024 growth : Uint4B/8B +0x0c8 mem_pressure : Uint4B : 200 +0x0cc mechanisms : [3] Uint4B : 204 (expand), 208 (compact), 212 (concurrent_compact) +0x0d8 gen_condemn_reasons : Uint4B : 216 +0x0dc heap_index : Uint4B : 220 clrInstanceId : byte : 224 vm\gcrecord.h Etw_GCDataPerHeapSpecial(...) ... EventDataDescCreate(EventData[0], gc_data_per_heap, datasize); EventDataDescCreate(EventData[1], ClrInstanceId, sizeof(ClrInstanceId)); Version 1: ??? Version 2, PreciseVersion 2.1: .NET 4.5 (x86) 0:000> dt -r2 WKS::gc_history_per_heap clr!WKS::gc_history_per_heap +0x000 gen_data : [5] WKS::gc_generation_data +0x000 size_before : Uint4B/8B : [0 - 40), [40 - 80), [80 - 120), [120 - 160), [160 - 200) +0x004 free_list_space_before : Uint4B/8B +0x008 free_obj_space_before : Uint4B/8B +0x00c size_after : Uint4B/8B +0x010 free_list_space_after : Uint4B/8B +0x014 free_obj_space_after : Uint4B/8B +0x018 in : Uint4B/8B +0x01c out : Uint4B/8B +0x020 new_allocation : Uint4B/8B +0x024 surv : Uint4B/8B +0x0c8 gen_to_condemn_reasons : WKS::gen_to_condemn_tuning +0x000 condemn_reasons_gen : Uint4B : 200 +0x004 condemn_reasons_condition : Uint4B : 204 +0x0d0 mem_pressure : Uint4B : 208 +0x0d4 mechanisms : [2] Uint4B : 212 (expand), 216 (compact) +0x0dc heap_index : Uint4B : 220 vm\gcrecord.h Etw_GCDataPerHeapSpecial(...) ... EventDataDescCreate(EventData[0], gc_data_per_heap, datasize); EventDataDescCreate(EventData[1], ClrInstanceId, sizeof(ClrInstanceId)); Version 2, PreciseVersion 2.2: .NET 4.5.2 (x86) 0:000> dt -r2 WKS::gc_history_per_heap clr!WKS::gc_history_per_heap +0x000 gen_data : [5] WKS::gc_generation_data +0x000 size_before : Uint4B/8B : [0 - 40), [40 - 80), [80 - 120), [120 - 160), [160 - 200) +0x004 free_list_space_before : Uint4B/8B +0x008 free_obj_space_before : Uint4B/8B +0x00c size_after : Uint4B/8B +0x010 free_list_space_after : Uint4B/8B +0x014 free_obj_space_after : Uint4B/8B +0x018 in : Uint4B/8B +0x01c out : Uint4B/8B +0x020 new_allocation : Uint4B/8B +0x024 surv : Uint4B/8B +0x0c8 gen_to_condemn_reasons : WKS::gen_to_condemn_tuning +0x000 condemn_reasons_gen : Uint4B : 200 +0x004 condemn_reasons_condition : Uint4B : 204 +0x0d0 mem_pressure : Uint4B : 208 +0x0d4 mechanisms : [2] Uint4B : 212 (expand), 216 (compact) +0x0dc heap_index : Uint4B : 220 +0x0e0 extra_gen0_committed : Uint8B : 224 vm\gcrecord.h Etw_GCDataPerHeapSpecial(...) ... EventDataDescCreate(EventData[0], gc_data_per_heap, datasize); EventDataDescCreate(EventData[1], ClrInstanceId, sizeof(ClrInstanceId)); Version 3: .NET 4.6 (x86) 0:000> dt -r2 WKS::gc_history_per_heap clr!WKS::gc_history_per_heap +0x000 gen_data : [4] WKS::gc_generation_data +0x000 size_before : Uint4B/8B +0x004 free_list_space_before : Uint4B/8B +0x008 free_obj_space_before : Uint4B/8B +0x00c size_after : Uint4B/8B +0x010 free_list_space_after : Uint4B/8B +0x014 free_obj_space_after : Uint4B/8B +0x018 in : Uint4B/8B +0x01c pinned_surv : Uint4B/8B +0x020 npinned_surv : Uint4B/8B +0x024 new_allocation : Uint4B/8B +0x0a0 maxgen_size_info : WKS::maxgen_size_increase +0x000 free_list_allocated : Uint4B/8B +0x004 free_list_rejected : Uint4B/8B +0x008 end_seg_allocated : Uint4B/8B +0x00c condemned_allocated : Uint4B/8B +0x010 pinned_allocated : Uint4B/8B +0x014 pinned_allocated_advance : Uint4B/8B +0x018 running_free_list_efficiency : Uint4B/8B +0x0bc gen_to_condemn_reasons : WKS::gen_to_condemn_tuning +0x000 condemn_reasons_gen : Uint4B +0x004 condemn_reasons_condition : Uint4B +0x0c4 mechanisms : [2] Uint4B +0x0cc machanism_bits : Uint4B +0x0d0 heap_index : Uint4B +0x0d4 extra_gen0_committed : Uint4B/8B pal\src\eventprovider\lttng\eventprovdotnetruntime.cpp FireEtXplatGCPerHeapHistory_V3(...) tracepoint( DotNETRuntime, GCPerHeapHistory_V3, x86 offsets ClrInstanceID, : 0 (const size_t) FreeListAllocated, : 2 (const size_t) FreeListRejected, : 6 (const size_t) EndOfSegAllocated, : 10 (const size_t) CondemnedAllocated, : 14 (const size_t) PinnedAllocated, : 18 (const size_t) PinnedAllocatedAdvance, : 22 RunningFreeListEfficiency, : 26 CondemnReasons0, : 30 CondemnReasons1 : 34 ); tracepoint( DotNETRuntime, GCPerHeapHistory_V3_1, CompactMechanisms, : 38 ExpandMechanisms, : 42 HeapIndex, : 46 (const size_t) ExtraGen0Commit, : 50 Count, : 54 (number of WKS::gc_generation_data's) Arg15_Struct_Len_, : ?? not really sent (const int*) Arg15_Struct_Pointer_ : [58 - 98), ... ); Version 3 is now setup to allow "add to the end" scenarios Returns the condemned generation number Returns the condemned condition genNumber is a number from 0 to maxGenData-1. These are for generation 0, 1, 2, 3 = Large Object Heap genNumber = 4 is that second pass for Gen 0. Version 0: Silverlight (x86), .NET 4.0 [5] WKS::gc_generation_data +0x000 size_before : Uint4B/8B +0x004 size_after : Uint4B/8B +0x008 current_size : Uint4B/8B +0x00c previous_size : Uint4B/8B +0x010 fragmentation : Uint4B/8B +0x014 in : Uint4B/8B +0x018 out : Uint4B/8B +0x01c new_allocation : Uint4B/8B +0x020 surv : Uint4B/8B +0x024 growth : Uint4B/8B Version 1: ??? Version 2, PreciseVersion 2.1: .NET 4.5 (x86), .NET 4.5.2 (x86) [5] WKS::gc_generation_data +0x000 size_before : Uint4B/8B +0x004 free_list_space_before : Uint4B/8B +0x008 free_obj_space_before : Uint4B/8B +0x00c size_after : Uint4B/8B +0x010 free_list_space_after : Uint4B/8B +0x014 free_obj_space_after : Uint4B/8B +0x018 in : Uint4B/8B +0x01c out : Uint4B/8B +0x020 new_allocation : Uint4B/8B +0x024 surv : Uint4B/8B Version 3: .NET 4.6 (x86) [4] WKS::gc_generation_data +0x000 size_before : Uint4B/8B +0x004 free_list_space_before : Uint4B/8B +0x008 free_obj_space_before : Uint4B/8B +0x00c size_after : Uint4B/8B +0x010 free_list_space_after : Uint4B/8B +0x014 free_obj_space_after : Uint4B/8B +0x018 in : Uint4B/8B +0x01c pinned_surv : Uint4B/8B +0x020 npinned_surv : Uint4B/8B +0x024 new_allocation : Uint4B/8B Size of the generation before the GC, includes fragmentation Size of the generation after GC. Includes fragmentation Size occupied by objects at the beginning of the GC, discounting fragmentation. Only exits on 4.5 RC and beyond. This is the fragmenation at the end of the GC. Size occupied by objects, discounting fragmentation. This is the free list space (ie, what's threaded onto the free list) at the beginning of the GC. Only exits on 4.5 RC and beyond. This is the free obj space (ie, what's free but not threaded onto the free list) at the beginning of the GC. Only exits on 4.5 RC and beyond. This is the free list space (ie, what's threaded onto the free list) at the end of the GC. Only exits on 4.5 Beta and beyond. This is the free obj space (ie, what's free but not threaded onto the free list) at the end of the GC. Only exits on 4.5 Beta and beyond. This is the amount that came into this generation on this GC This is the number of bytes survived in this generation. This is the new budget for the generation This is the survival rate Version 0: ??? Version 1: Silverlight (x86), .NET 4.0, .NET 4.5, .NET 4.5.2 VM\gc.cpp 0:041> dt -r3 WKS::gc_history_global coreclr!WKS::gc_history_global +0x000 final_youngest_desired : Uint4B/8B +0x004 num_heaps : Uint4B +0x008 condemned_generation : Int4B +0x00c gen0_reduction_count : Int4B +0x010 reason : reason_alloc_soh = 0n0 reason_induced = 0n1 reason_lowmemory = 0n2 reason_empty = 0n3 reason_alloc_loh = 0n4 reason_oos_soh = 0n5 reason_oos_loh = 0n6 reason_induced_noforce = 0n7 reason_gcstress = 0n8 reason_max = 0n9 +0x014 global_mechanims_p : Uint4B FireEtwGCGlobalHeapHistory_V1(gc_data_global.final_youngest_desired, // upcast on 32bit to __int64 gc_data_global.num_heaps, gc_data_global.condemned_generation, gc_data_global.gen0_reduction_count, gc_data_global.reason, gc_data_global.global_mechanims_p, GetClrInstanceId()); Version 2: .NET 4.6 clr!WKS::gc_history_global +0x000 final_youngest_desired : Uint4B/8B +0x004 num_heaps : Uint4B +0x008 condemned_generation : Int4B +0x00c gen0_reduction_count : Int4B +0x010 reason : reason_alloc_soh = 0n0 reason_induced = 0n1 reason_lowmemory = 0n2 reason_empty = 0n3 reason_alloc_loh = 0n4 reason_oos_soh = 0n5 reason_oos_loh = 0n6 reason_induced_noforce = 0n7 reason_gcstress = 0n8 reason_lowmemory_blocking = 0n9 reason_induced_compacting = 0n10 reason_lowmemory_host = 0n11 reason_max = 0n12 +0x014 pause_mode : Int4B +0x018 mem_pressure : Uint4B +0x01c global_mechanims_p : Uint4B FireEtwGCGlobalHeapHistory_V2(gc_data_global.final_youngest_desired, // upcast on 32bit to __int64 gc_data_global.num_heaps, gc_data_global.condemned_generation, gc_data_global.gen0_reduction_count, gc_data_global.reason, gc_data_global.global_mechanims_p, GetClrInstanceId()); gc_data_global.pause_mode, gc_data_global.mem_pressure); Gets the full type name including generic parameters in runtime syntax For example System.WeakReference`1[System.Diagnostics.Tracing.EtwSession] Returns the CCW at the given zero-based index (index less than Count). The returned GCBulkRootCCWValues points the the data in GCBulkRootCCWTraceData so it cannot live beyond that lifetime. Computes the size of one GCBulkRootCCWValues structure. TODO FIX NOW Can rip out and make a constant 44 after 6/2014 This structure just POINTS at the data in the GCBulkRootCCWTraceData. It can only be used as long as the GCBulkRootCCWTraceData is alive which (unless you cloned it) is only for the lifetime of the callback. Returns the edge at the given zero-based index (index less than Count). The returned GCBulkRCWValues points the the data in GCBulkRCWTraceData so it cannot live beyond that lifetime. This structure just POINTS at the data in the GCBulkRCWTraceData. It can only be used as long as the GCBulkRCWTraceData is alive which (unless you cloned it) is only for the lifetime of the callback. Returns 'idx'th static root. The returned GCBulkRootStaticVarStatics cannot live beyond the TraceEvent that it comes from. The implementation is highly tuned for sequential access. This structure just POINTS at the data in the GCBulkRootStaticVarTraceData. It can only be used as long as the GCBulkRootStaticVarTraceData is alive which (unless you cloned it) is only for the lifetime of the callback. Fetches the instruction pointer of a eventToStack frame 0 is the deepest frame, and the maximum should be a thread offset routine (if you get a complete eventToStack). The index of the frame to fetch. 0 is the CPU EIP, 1 is the Caller of that routine ... The instruction pointer of the specified frame. Access to the instruction pointers as a unsafe memory blob This is simply the file name part of the ModuleILPath. It is a convenience method. Log events associated with the threadpool, and other threading events. Dump the native to IL mapping of any method that is JIT compiled. (V4.5 runtimes and above). This suppresses NGEN events on V4.0 (where you have NGEN PDBs), but not on V2.0 (which does not know about this bit and also does not have NGEN PDBS). TODO document Dump PDBs for dynamically generated modules. Events that provide information about compilation. ClrTraceEventParserState holds all information that is shared among all events that is needed to decode Clr events. This class is registered with the source so that it will be persisted. Things in here include * TypeID to TypeName mapping, Returns the edge at the given zero-based index (index less than Count). The returned BulkNodeValues points the the data in BulkNodeTraceData so it cannot live beyond that lifetime. This structure just POINTS at the data in the BulkNodeTraceData. It can only be used as long as the BulkNodeTraceData is alive which (unless you cloned it) is only for the lifetime of the callback. Returns the edge at the given zero-based index (index less than Count). The returned BulkAttributeValues points the the data in BulkAttributeTraceData so it cannot live beyond that lifetime. This structure just POINTS at the data in the BulkAttributeTraceData. It can only be used as long as the BulkAttributeTraceData is alive which (unless you cloned it) is only for the lifetime of the callback. Returns the edge at the given zero-based index (index less than Count). The returned BulkEdgeValues points the the data in BulkEdgeTraceData so it cannot live beyond that lifetime. This structure just POINTS at the data in the BulkNodeTraceData. It can only be used as long as the BulkNodeTraceData is alive which (unless you cloned it) is only for the lifetime of the callback. The KernelTraceEventParser is a class that knows how to decode the 'standard' kernel events. It exposes an event for each event of interest that users can subscribe to. see TraceEventParser for more The special name for the Kernel session This is passed to TraceEventSession.EnableKernelProvider to enable particular sets of events. See http://msdn.microsoft.com/en-us/library/aa363784(VS.85).aspx for more information on them Logs nothing Logs the mapping of file IDs to actual (kernel) file names. Loads the completion of Physical disk activity. Logs native modules loads (LoadLibrary), and unloads Logs all page faults that must fetch the data from the disk (hard faults) Logs TCP/IP network send and receive events. Logs process starts and stops. Logs process performance counters (TODO When?) (Vista+ only) see KernelTraceEventParser.ProcessPerfCtr, ProcessPerfCtrTraceData Sampled based profiling (every msec) (Vista+ only) (expect 1K events per proc per second) Logs threads starts and stops log thread context switches (Vista only) (can be > 10K events per second) log Disk operations (Vista+ only) Generally not TOO volumous (typically less than 1K per second) (Stacks associated with this) Thread Dispatcher (ReadyThread) (Vista+ only) (can be > 10K events per second) log file FileOperationEnd (has status code) when they complete (even ones that do not actually cause Disk I/O). (Vista+ only) Generally not TOO volumous (typically less than 1K per second) (No stacks associated with these) log the start of the File I/O operation as well as the end. (Vista+ only) Generally not TOO volumous (typically less than 1K per second) Logs all page faults (hard or soft) Can be pretty volumous (> 1K per second) Logs activity to the windows registry. Can be pretty volumous (> 1K per second) log calls to the OS (Vista+ only) This is VERY volumous (can be > 100K events per second) Log Virtual Alloc calls and VirtualFree. (Vista+ Only) Generally not TOO volumous (typically less than 1K per second) Log mapping of files into memory (Win8 and above Only) Generally low volume. Logs Advanced Local Procedure call events. log defered procedure calls (an Kernel mechanism for having work done asynchronously) (Vista+ only) Device Driver logging (Vista+ only) log hardware interrupts. (Vista+ only) Disk I/O that was split (eg because of mirroring requirements) (Vista+ only) Good default kernel flags. (TODO more detail) These events are too verbose for normal use, but this give you a quick way of turing on 'interesting' events This does not include SystemCall because it is 'too verbose' Use this if you care about blocked time. You mostly don't care about these unless you are dealing with OS internals. All legal kernel events These are the kernel events that are not allowed in containers. Can be subtracted out. Turn on PMC (Precise Machine Counter) events. Only Win 8 Kernel reference set events (like XPERF ReferenceSet). Fully works only on Win 8. Events when thread priorities change. Events when queuing and dequeuing from the I/O completion ports. Handle creation and closing (for handle leaks) These keywords can't be passed to the OS, they are defined by KernelTraceEventParser What his parser should track by default. Defines how kernel paths are converted to user paths. Setting it overrides the default path conversion mechanism. Registers both ProcessStart and ProcessDCStart Registers both ProcessEnd and ProcessDCStop Registers both ThreadStart and ThreadDCStart Registers both ThreadEnd and ThreadDCStop Registers both ImageLoad and ImageDCStart Registers both ImageUnload and ImageDCStop Rasied every 0.5s with memory metrics of the current machine. File names in ETW are the Kernel names, which need to be mapped to the drive specification users see. This event indicates this mapping. KernelTraceEventParserState holds all information that is shared among all events that is needed to decode kernel events. This class is registered with the source so that it will be persisted. Things in here include * FileID to FileName mapping, * ThreadID to ProcessID mapping * Kernel file name to user file name mapping If you have a file object (per-open-file) in addition to a fileKey, try using both to look up the file name. This is for the circular buffer case. In that case we may not have thread starts (and thus we don't have entries in threadIDtoProcessID). Because HistoryTable finds the FIRST entry GREATER than the given threadID we NEGATE all times before we place it in this table. Also, because circular buffering is not the common case, we only add entries to this table if needed (if we could not find the thread ID using threadIDtoProcessID). Keeps track of the mapping from kernel names to file system names (drives) Create a new KernelToUserDriveMapping that can look up kernel names for drives and map them to windows drive letters. Returns the string representing the windows drive letter for the kernel drive name 'kernelName' This is the number of minutes between the local time where the data was collected and UTC time. It does NOT take Daylight savings time into account. It is positive if your time zone is WEST of Greenwich. Indicate that StartAddr and Win32StartAddr are a code addresses that needs symbolic information We report a context switch from from the new thread. Thus NewThreadID == ThreadID. The I/O Response Packet address. This represents the 'identity' of this particular I/O This is the time since the I/O was initiated, in source.PerfFreq (QPC) ticks. This is the actual time the disk spent servicing this IO. Same as elapsed time for real time providers. The time since the I/O was initiated. This is the time since the I/O was initiated, in source.PerfFreq (QPC) ticks. The time since the I/O was initiated. This is a handle that represents a file NAME (not an open file). In the MSDN does this field is called FileObject. However in other events FileObject is something returned from Create file and is different. Events have have both (and some do) use FileKey. Thus I use FileKey uniformly to avoid confusion. See the Windows CreateFile API CreateOptions for this See Windows CreateFile API CreateDisposition for this. See Windows CreateFile API ShareMode parameter See windows CreateFile API ShareMode parameter See Windows CreateFile function CreateDispostion parameter. The enum written to the ETW trace is the Disposition parameter passed to IoCreateFileSpecifyDeviceObjectHint. See Windows CreateFile function FlagsAndAttributes parameter. TODO FIX NOW: these have not been validated yet. The FileObject is the object for the Directory (used by CreateFile to open and passed to Close to close) The FileKey is the object that represents the name of the directory. This is the TimeDateStamp converted to a DateTime TODO: daylight savings time seems to mess this up. Indicate that ProgramCounter is a code address that needs symbolic information The time spent during the page fault. Indicate that the Address is a code address that needs symbolic information This event is emitted by the Microsoft-Windows-Kernel-Memory with Keyword 0x40 KERNEL_MEM_KEYWORD_MEMINFO_EX every .5 seconds Returns the edge at the given zero-based index (index less than Count). The returned MemoryProcessMemInfoValues points the the data in MemoryProcessMemInfoTraceData so it cannot live beyond that lifetime. The fields after 'Count' are the first value in the array of working sets. This structure just POINTS at the data in the MemoryProcessMemInfoTraceData. It can only be used as long as the MemoryProcessMemInfoTraceData is alive which (unless you cloned it) is only for the lifetime of the callback. The fields after 'Count' are the first value in the array of working sets. Are we currently executing a Deferred Procedure Call (a mechanism the kernel uses to 'steal' a thread to run its own work). If this is true, the CPU time is really not logically related to the process (it is kernel time). Are we currently executing a Interrupt Service Routine? Like ExecutingDPC if this is true the thread is really doing Kernel work, not work for the process. NonProcess is true if ExecutingDPC or ExecutingISR is true. The thread's current priority (higher is more likely to run). A normal thread with a normal base priority is 8. see http://msdn.microsoft.com/en-us/library/windows/desktop/ms685100(v=vs.85).aspx for more Your scheduling If the thread is not part of a scheduling group, this is 0 (see callout.c) Indicate that the Address is a code address that needs symbolic information PMC (Precise Machine Counter) events are fired when a CPU counter trips. The the ProfileSource identifies which counter it is. The PerfInfoCollectionStart events will tell you the count that was configured to trip the event. Indicate that Address is a code address that needs symbolic information Indicate that the Address is a code address that needs symbolic information Collects the call callStacks for some other event. (TODO: always for the event that preceded it on the same thread)? The timestamp of the event which caused this stack walk using QueryPerformaceCounter cycles as the tick. Converts this to a time relative to the start of the trace in msec. The total number of eventToStack frames collected. The Windows OS currently has a maximum of 96 frames. Fetches the instruction pointer of a eventToStack frame 0 is the deepest frame, and the maximum should be a thread offset routine (if you get a complete stack). The index of the frame to fetch. 0 is the CPU EIP, 1 is the Caller of that routine ... The instruction pointer of the specified frame. Access to the instruction pointers as a unsafe memory blob StackWalkTraceData does not set Thread and process ID fields properly. if that. To save space, stack walks in Win8 can be complressed. The stack walk event only has a reference to a stack Key which is then looked up by StackWalkDefTraceData. The timestamp of the event which caused this stack walk using QueryPerformaceCounter cycles as the tick. Converts this to a time relative to the start of the trace in msec. Returns a key that can be used to look up the stack in KeyDelete or KeyRundown events StackWalkTraceData does not set Thread and process ID fields properly. if that. This event defines a stack and gives it a unique id (the StackKey), which StackWalkRefTraceData can point at. Returns a key that can be used to look up the stack in KeyDelete or KeyRundown events The total number of eventToStack frames collected. The Windows OS currently has a maximum of 96 frames. Fetches the instruction pointer of a eventToStack frame 0 is the deepest frame, and the maximum should be a thread offset routine (if you get a complete complete). The index of the frame to fetch. 0 is the CPU EIP, 1 is the Caller of that routine ... The instruction pointer of the specified frame. Access to the instruction pointers as a unsafe memory blob e.g. c:\windows\system32 .e.g c:\windows Sees if up to 'max' bytes of frag-fragend is a printable string and if so prints it to 'sb' with 'prefix' before it. Kernel traces have information about images that are loaded, however they don't have enough information in the events themselves to unambigously look up PDBs without looking at the data inside the images. This means that symbols can't be resolved unless you are on the same machine on which you gathered the data. XPERF solves this problem by adding new 'synthetic' events that it creates by looking at the trace and then opening each DLL mentioned and extracting the information needed to look PDBS up on a symbol server (this includes the PE file's TimeDateStamp as well as a PDB Guid, and 'pdbAge' that can be found in the DLLs header. These new events are added when XPERF runs the 'merge' command (or -d flag is passed). It is also exposed through the KernelTraceControl.dll!CreateMergedTraceFile API. SymbolTraceEventParser is a parser for extra events. The DbgIDRSDS event is added by XPERF for every Image load. It contains the 'PDB signature' for the DLL, which is enough to unambiguously look the image's PDB up on a symbol server. Every DLL has a Timestamp in the PE file itself that indicates when it is built. This event dumps this timestamp. This timestamp is used to be as the 'signature' of the image and is used as a key to find the symbols, however this has mostly be superseded by the DbgID/RSDS event. The FileVersion event contains information from the file version resource that most DLLs have that indicated detailed information about the exact version of the DLL. (What is in the File->Properties->Version property page) I don't really care about this one, but I need a definition in order to exclude it because it has the same timestamp as a imageLoad event, and two events with the same timestamp confuse the association between a stack and the event for the stack. This event has a TRACE_EVENT_INFO as its payload, and allows you to decode an event The event describes a Map (bitmap or ValueMap), and has a payload as follows GUID ProviderId; EVENT_MAP_INFO EventMapInfo; The value of the one string payload property. Construct a TraceEvent template which has one string payload field with the given metadata and action implementation of TraceEvent Interface. implementation of TraceEvent Interface. implementation of TraceEvent Interface. implementation of TraceEvent Interface. override RegisteredTraceEventParser uses the standard windows provider database (TDH, what gets registered with wevtutil) to find the names of events and fields of the events). Create a new RegisteredTraceEventParser and attach it to the given TraceEventSource Given a provider name that has been registered with the operating system, get a string representing the ETW manifest for that provider. Note that this manifest is not as rich as the original source manifest because some information is not actually compiled into the binary manifest that is registered with the OS. Given a provider GUID that has been registered with the operating system, get a string representing the ETW manifest for that provider. Note that this manifest is not as rich as the original source manifest because some information is not actually compiled into the binary manifest that is registered with the OS. Generates a space separated list of set of keywords 'keywordSet' using the table 'keywords' It will generate new keyword names if needed and add them to 'keywords' if they are not present. Class used to accumulate information about Tasks in the implementation of GetManifestForRegisteredProvider Try to look up 'unknonwEvent using TDH or the TraceLogging mechanism. if 'mapTable' is non-null it will be used look up the string names for fields that have bitsets or enumerated values. This is only need for the KernelTraceControl case where the map information is logged as special events and can't be looked up with TDH APIs. TdhEventParser takes the Trace Diagnostics Helper (TDH) TRACE_EVENT_INFO structure and (passed as a byte*) and converts it to a DynamicTraceEventData which which can be used to parse events of that type. You first create TdhEventParser and then call ParseEventMetaData to do the parsing. Creates a new parser from the TRACE_EVENT_INFO held in 'buffer'. Use ParseEventMetaData to then parse it into a DynamicTraceEventData structure. EventRecord can be null and mapTable if present allow the parser to resolve maps (enums), and can be null. Actually performs the parsing of the TRACE_EVENT_INFO passed in the constructor Parses at most 'maxFields' fields starting at the current position. Will return the parse fields in 'payloadNamesRet' and 'payloadFetchesRet' Will return true if successful, false means an error occurred. ExternalTraceEventParser is an abstract class that acts as a parser for any 'External' resolution This include the TDH (RegisteredTraceEventParser) as well as the WPPTraceEventParser. Create a new ExternalTraceEventParser and attach it to the given TraceEventSource Override. Override Returns true if the RegisteredTraceEventParser would return 'template' in EnumerateTemplates override Register 'template' so that if there are any subscriptions to template they get registered with the source. Used to look up Enums (provider x enumName); Very boring class. TDHDynamicTraceEventParserState represents the state of a TDHDynamicTraceEventParser that needs to be serialized to a log file. It does NOT include information about what events are chosen but DOES contain any other necessary information that came from the ETL data file or the OS TDH APIs. This defines what it means to be the same event. For manifest events it means provider and event ID for classic, it means that taskGuid and opcode match. Implements IFastSerializable interface Implements IFastSerializable interface This parser knows how to decode Windows Software Trace Preprocessor (WPP) events. In order to decode the events it needs access to the TMF files that describe the events (these are created from the PDB at build time).
You will generally use this for the 'FormattedMessage' property of the event.
Construct a new WPPTraceEventParser that is attached to 'source'. Once you do this the source will understand WPP events. In particular you can subscribe to the Wpp.All event to get the stream of WPP events in the source. For WppTraceEventParser to function, it needs the TMF files for the events it will decode. You should pass the directory to find these TMF files in 'TMFDirectory'. Each file should have the form of a GUID.tmf. ETWReloggerTraceEventSource is designed to be able to write ETW files using an existing ETW input stream (either a file, files or real time session) as a basis. The relogger capabilities only exist on Windows 8 OSes and beyond. The right way to think about this class is that it is just like ETWTraceEventSource, but it also has a output file associated with it, and WriteEvent APIs that can be used to either copy events from the event stream (the common case), or inject new events (high level stats). Create an ETWReloggerTraceEventSource that can takes its input from the family of etl files inputFileName and can write them to the ETL file outputFileName (.kernel*.etl, .user*.etl .clr*.etl) This is a shortcut for ETWReloggerTraceEventSource(inputFileName, TraceEventSourceType.MergeAll, outputFileStream) Create an ETWReloggerTraceEventSource that can takes its input from a variety of sources (either a single file, a set of files, or a real time ETW session (based on 'type'), and can write these events to a new ETW output file 'outputFileName. The output file can use a compressed form or not. Compressed forms can only be read on Win8 and beyond. Defaults to true. Writes an event from the input stream to the output stream of events. Connect the given EventSource so any events logged from it will go to the output stream of events. Once connected, you may only write events from this EventSource while processing the input stream (that is during the callback of an input stream event), because the context for the EventSource event (e.g. timestamp, proesssID, threadID ...) will be derived from the current event being processed by the input stream. Writes an event that did not exist previously into the data stream, The context data (time, process, thread, activity, comes from 'an existing event') Writes an event that did not exist previously into the data stream, The context data (time, process, thread, activity, comes from 'an existing event') is given explicitly implementing TraceEventDispatcher implementing TraceEventDispatcher Implements TraceEventDispatcher.Dispose Implements TraceEventDispatcher.StopProcessing This is used by the ConnectEventSource to route events from the EventSource to the relogger. This is the class the Win32 APIs call back on. A ETWTraceEventSource represents the stream of events that was collected from a TraceEventSession (eg the ETL moduleFile, or the live session event stream). Like all TraceEventSource, it logically represents a stream of TraceEvent s. Like all TraceEventDispathers it supports a callback model where Parsers attach themselves to this sources, and user callbacks defined on the parsers are called when the 'Process' method is called. * See also TraceEventDispatcher * See also TraceEvent * See also #ETWTraceEventSourceInternals * See also #ETWTraceEventSourceFields Open a ETW event trace moduleFile (ETL moduleFile) for processing. The ETL data moduleFile to open` Open a ETW event source for processing. This can either be a moduleFile or a real time ETW session If type == ModuleFile this is the name of the moduleFile to open. If type == Session this is the name of real time session to open. Open multiple etl files as one trace for processing. If type == MergeAll, call Initialize. Process all the files in 'fileNames' in order (that is all the events in the first file are processed, then the second ...). Intended for parsing the 'Multi-File' collection mode. The list of files path names to process (in that order) Processes all the events in the data source, issuing callbacks that were subscribed to. See #Introduction for more false If StopProcesing was called Reprocess a pre-constructed event which this processor has presumably created. Helpful to re-examine "unknown" events, perhaps after a manifest has been received from the ETW stream. Note when queuing events to reprocess you must Clone them first or certain internal data may no longer be available and you may receive memory access violations. Event to re-process. The log moduleFile that is being processed (if present) TODO: what does this do for Real time sessions? The name of the session that generated the data. The size of the log, will return 0 if it does not know. returns the number of events that have been lost in this session. Note that this value is NOT updated for real time sessions (it is a snapshot). Instead you need to use the TraceEventSession.EventsLost property. Returns true if the Process can be called multiple times (if the Data source is from a moduleFile, not a real time stream. This routine is only useful/valid for real-time sessions. TraceEvent.TimeStamp internally is stored using a high resolution clock called the Query Performance Counter (QPC). This clock is INDEPENDENT of the system clock used by DateTime. These two clocks are synchronized to within 2 msec at session startup but they can drift from there (typically 2msec / min == 3 seconds / day). Thus if you have long running real time session it becomes problematic to compare the timestamps with those in another session or something timestamped with the system clock. SynchronizeClock will synchronize the TraceEvent.Timestamp clock with the system clock again. If you do this right before you start another session, then the two sessions will be within 2 msec of each other, and their timestamps will correlate. Doing it periodically (e.g. hourly), will keep things reasonably close. TODO: we can achieve perfect synchronization by exposing the QPC tick sync point so we could read the sync point from one session and set that exact sync point for another session. Options that can be passed to GetModulesNeedingSymbols This is the default, where only NGEN images are included (since these are the only images whose PDBS typically need to be resolved aggressively AT COLLECTION TIME) If set, this option indicates that non-NGEN images should also be included in the list of returned modules Normally only modules what have a CPU or stack sample are included in the list of assemblies (thus you don't unnecessarily have to generate NGEN PDBS for modules that will never be looked up). However if there are events that have addresses that need resolving that this routine does not recognise, this option can be set to ensure that any module that was event LOADED is included. This is inefficient, but guaranteed to be complete Given an ETL file, returns a list of the full paths to DLLs that were loaded in the trace that need symbolic information (PDBs) so that the stack traces and CPU samples can be properly resolved. By default this only returns NGEN images since these are the ones that need to be resolved and generated at collection time. Image data is a trivial record for image data, where it is keyed by the base address, processID and name. Returns the size of pointer (8 or 4) for the operating system (not necessarily the process) This is a little helper class that maps QueryPerformanceCounter (QPC) ticks to DateTime. There is an error of a few msec, but as long as every one uses the same one, we probably don't care. see Dispose pattern see Dispose pattern Used by real time TraceLog on Windows7. If we have several real time sources we have them coming in on several threads, but we want the illusion that they are one source (thus being processed one at a time). Thus we want a lock that is taken on every dispatch. The kinds of data sources that can be opened (see ETWTraceEventSource) Look for any files like *.etl or *.*.etl (the later holds things like *.kernel.etl or *.clrRundown.etl ...) Look for a ETL moduleFile *.etl as the event data source Use a real time session as the event data source. After all events have been parsed we could have some straglers that weren't earlier than any sorted event. Sort and dispatch those now. Fetches the instruction pointer of a eventToStack frame 0 is the deepest frame, and the maximum should be a thread offset routine (if you get a complete eventToStack). The index of the frame to fetch. 0 is the CPU EIP, 1 is the Caller of that routine ... The instruction pointer of the specified frame. Access to the instruction pointers as a unsafe memory blob EventPipeEventSource knows how to decode EventPipe (generated by the .NET core runtime). Please see for details on the file format. By conventions files of such a format are given the .netperf suffix and are logically very much like a ETL file in that they have a header that indicate things about the trace as a whole, and a list of events. Like more modern ETL files the file as a whole is self-describing. Some of the events are 'MetaData' events that indicate the provider name, event name, and payload field names and types. Ordinary events then point at these meta-data event so that logically all events have a name some basic information (process, thread, timestamp, activity ID) and user defined field names and values of various types. This is the version number reader and writer (although we don't don't have a writer at the moment) It MUST be updated (as well as MinimumReaderVersion), if breaking changes have been made. If your changes are forward compatible (old readers can still read the new format) you don't have to update the version number but it is useful to do so (while keeping MinimumReaderVersion unchanged) so that readers can quickly determine what new content is available. This field is only used for writers, and this code does not have writers so it is not used. It should be set to Version unless changes since the last version are forward compatible (old readers can still read this format), in which case this should be unchanged. This is the smallest version that the deserializer here can read. Currently we are careful about backward compat so our deserializer can read anything that has ever been produced. We may change this when we believe old writers basically no longer exist (and we can remove that support code). Given the EventPipe metaData header and a stream pointing at the serialized meta-data for the parameters for the event, create a new DynamicTraceEventData that knows how to parse that event. ReaderForParameters.Current is advanced past the parameter information. The Nettrace format is divided up into various blocks - this is a base class that handles the common aspects for all of them. An EVentPipeEventBlock represents a block of events. It basically only has one field, which is the size in bytes of the block. But when its FromStream is called, it will perform the callbacks for the events (thus deserializing it performs dispatch). A block of metadata carrying events. These 'events' aren't dispatched by EventPipeEventSource - they carry the metadata that allows the payloads of non-metadata events to be decoded. An EventPipeSequencePointBlock represents a stream divider that contains updates for all thread event sequence numbers, indicates that all queued events can be sorted and dispatched, and that all cached events/stacks can be flushed. An EventPipeStackBlock represents a block of interned stacks. Events refer to stacks by an id. Private utility class. An EventPipeEventMetaDataHeader holds the information that can be shared among all instances of an EventPipe event from a particular provider. Thus it contains things like the event name, provider, It however does NOT contain the data about the event parameters (the names of the fields and their types), That is why this is a meta-data header and not all the meta-data. This class has two main functions 1. The constructor takes a PinnedStreamReader and decodes the serialized metadata so you can access the data conveniently (but it does not decode the parameter info) 2. It remembers a EVENT_RECORD structure (from ETW) that contains this data) and has a function GetEventRecordForEventData which converts from a EventPipeEventHeader (the raw serialized data) to a EVENT_RECORD (which is what TraceEvent needs to look up the event an pass it up the stack. Creates a new MetaData instance from the serialized data at the current position of 'reader' of length 'length'. This typically points at the PAYLOAD AREA of a meta-data events) 'fileFormatVersionNumber' is the version number of the file as a whole (since that affects the parsing of this data) and 'processID' is the process ID for the whole stream (since it needs to be put into the EVENT_RECORD. When this constructor returns the reader has read up to the serialized information about the parameters. We do this because this code does not know the best representation for this parameter information and so it just lets other code handle it. Given a EventPipeEventHeader takes a EventPipeEventHeader that is specific to an event, copies it on top of the static information in its EVENT_RECORD which is specialized meta-data and returns a pointer to it. Thus this makes the EventPipe look like an ETW provider from the point of view of the upper level TraceEvent logic. This is a number that is unique to this meta-data blob. It is expected to be a small integer that starts at 1 (since 0 is reserved) and increases from there (thus an array can be used). It is what is matched up with EventPipeEventHeader.MetaDataId Reads the meta data for information specific to one event. Private utility class. At the start of every event from an EventPipe is a header that contains common fields like its size, threadID timestamp etc. EventPipeEventHeader is the layout of this. Events have two variable sized parts: the user defined fields, and the stack. EventPipEventHeader knows how to decode these pieces (but provides no semantics for it. It is not a public type, but used in low level parsing of EventPipeEventSource. Size of the event header + stack + payload (includes EventSize field itself) Header Size is defined to be the number of bytes before the Payload bytes. SampleInfos of a set of stackSource by eventToStack. This represents the entire call tree. You create an empty one in using the default constructor and use 'AddSample' to add stackSource to it. You traverse it by Creates an empty call tree, indicating the scaling policy of the metric. You populate it by assigning a StackSOurce to the tree. A CallTree is generated from a StackSource. Setting the StackSource causes the tree to become populated. When calculating percentages, the PercentageBasis do we use as 100%. By default we use the Inclusive time for the root, but that can be changed here. Returns the root node of the call tree. An upper bound for the node indexes in the call tree. (All indexes are strictly less than this number) Thus ASSSUMING YOU DON'T ADD NEW NODES, an array of this size can be used to index the nodes (and thus lookup nodes by index or to store additional information about a node). Get a CallerCalleeNode for the nodes in the call tree named 'nodeName' Returns a list of nodes that have statistics rolled up by treeNode by ID. It is not sorted by anything in particular. Note that ID is not quite the same thing as the name. You can have two nodes that have different IDs but the same Name. These will show up as two distinct entries in the resulting list. Returns the list returned by the ByID property sorted by exclusive metric. If there are any nodes that have strictly less than to 'minInclusiveMetric' then remove the node, placing its samples into its parent (thus the parent's exclusive metric goes up). If useWholeTraceMetric is true, nodes are only folded if their inclusive metric OVER THE WHOLE TRACE is less than 'minInclusiveMetric'. If false, then a node is folded if THAT NODE has less than the 'minInclusiveMetric' Thus if 'useWholeTraceMetric' == false then after calling this routine no node will have less than minInclusiveMetric. Cause the children of each CallTreeNode in the CallTree to be sorted (accending) based on comparer Sorting by InclusiveMetric Decending is so common, provide a shortcut. When converting the InclusiveMetricByTime to a InclusiveMetricByTimeString you have to decide how to scale the samples to the digits displayed in the string. This enum indicates this policy The nodes in the calltree have histograms in time, all of these histograms share a controller that contains sharable information. This propertly returns that TimeHistogramController The nodes in the calltree have histograms indexed by scenario (which is user defiend), all of these histograms share a controller that contains sharable information. This propertly returns that ScenarioHistogramController Turns off logic for computing call trees in parallel. Safer but slower. This is off by default following indications of race conditions. Break all links in the call tree to free as much memory as possible. Write an XML representtaion of the CallTree to 'writer' An XML representtaion of the CallTree (for debugging) Traverse the subtree of 'treeNode' into the m_sumByID dictionary. We don't want to double-count inclusive times, so we have to keep track of all callers currently on the stack and we only add inclusive times for nodes that are not already on the stack. ScalingPolicyKind represents the desired way to scale the metric in the samples. This is the default. In this policy, 100% is chosen so that the histogram is scaled as best it can. It assumes that the metric represents time Represents a unique ID for a node in a call tree. Can be used to look up a call tree node easily. It is a dense value (from 0 up to a maximum). An Invalid Node Index. A CallTreeNodeBase is the inforation in a CallTreeNode without parent or child relationships. ByName nodes and Caller-Callee nodes need this because they either don't have or need different parent-child relationships. Returns a unique small, dense number (suitable for looking up in an array) that represents this call tree node (unlike the ID, which more like the name of the frame of the node), so you can have many nodes with the same name, but only one with the same index. See CallTree.GetNodeIndexLimit. Create a CallTreeNodeBase (a CallTreeNode without children) which is a copy of another one. The Frame name that this tree node represents. Currently the same as Name, but could contain additional info. Suitable for display but not for programmatic comparison. The ID represents a most fine grained uniqueness associated with this node. It can represent a method, but for sources that support 'goto source' functionality these IDs actually represent particular lines (or more precisely program counter locations), within the method. Thus it is very likely that there are call tree nodes that have the same name but different IDs. This can be StackSourceFrameIndex.Invalid for Caller-callee nodes (which have names, but no useful ID) If ID != Invalid, and the IDs are the same then the names are guaranteed to be the same. The sum of the metric of all samples that are in this node or any child of this node (recursively) The average metric of all samples that are in this node or any child of this node (recursively). This is simply InclusiveMetric / InclusiveCount. The sum of the metric of all samples that are in this node The sum of the metric of all samples in this node that are there because they were folded (inlined). It is always less than or equal to ExclusiveMetric. The sum of the count of all samples that are in this node or any child of this node (recursively) The sum of the count of all samples that are in this node The sum of the count of all samples in this node that are there because they were folded (inlined). It is always less than or equal to ExclusiveCount. The inclusive metric, normalized to the total metric for the entire tree. The exclusive metric, normalized to the total metric for the entire tree. The exclusive folded metric, normalized to the total metric for the entire tree. The time of the first sample for this node or any of its children (recursively) The time of the first sample for this node or any of its children (recursively) The time of the last sample for this node or any of its children (recursively) The time of the last sample for this node or any of its children (recursively) The difference between the first and last sample (in MSec). The call tree that contains this node. Returns the histogram that groups of samples associated with this node or any of its children by time buckets Returns a string that represents the InclusiveMetricByTime Histogram by using character for every bucket (like PerfView) Returns the histogram that groups of samples associated with this node or any of its children by scenario buckets Returns a string that represents the InclusiveMetricByScenario Histogram by using character for every bucket (like PerfView) Returns all the original stack samples in this node. If exclusive==true then just he sample exclusively in this node are returned, otherwise it is the inclusive samples. If the original stack source that was used to create this CodeTreeNode was a FilterStackSource then that filtering is removed in the returned Samples. Returns the total number of samples (the number of times 'callback' is called) If the callback returns false, the iteration over samples stops. While 'GetSamples' can return all the samples in the tree, this is a relatively inefficient way of representing the samples. Instead you can return a list of trees whose samples represent all the samples. This is what GetTrees does. It calls 'callback' on a set of trees that taken as a whole have all the samples in 'node'. Note you ave to be careful when using this for inclusive summation of byname nodes because you will get trees that 'overlap' (bname nodes might refer into the 'middle' of another call tree). This can be avoided pretty easily by simply stopping inclusive traversal whenever a tree node with that ID occurs (see GetSamples for an example). Returns a string representing the set of XML attributes that can be added to another XML element. An XML representation of the CallTreeNodeBase (for debugging) The GUI sadly holds on to Call things in the model in its cache, and call tree nodes have linkes to whole call tree. To avoid the GUI cache from holding on to the ENTIRE MODEL, we neuter the nodes when we are done with them so that even if they are pointed to by the GUI cache it does not hold onto most of the (dead) model. FreeMemory does this neutering. Combines the 'this' node with 'otherNode'. If 'newOnStack' is true, then the inclusive metrics are also updated. Note that I DON'T accumulate other.m_samples into this.m_samples. This is because we want to share samples as much a possible. Thus nodes remember their samples by pointing at other call trees and you fetch the samples by an inclusive walk of the tree. To avoid double-counting for byname nodes, with we can be told to exclude any children with a particular ID (the ID of the ByName node itself) if are doing the inclusive case. The goal is to count every reachable tree exactly once. We do this by conceptually 'marking' each node with ID at the top level (when they are enumerated as children of the Byname node), and thus any node with that excludeChildrenWithID is conceptually marked if you encounter it as a child in the tree itself (so you should exclude it). The result is that every node is visited exactly once (without the expense of having a 'visited' bit). Represents a single treeNode in a CallTree Each node keeps all the sample with the same path to the root. Each node also remembers its parent (caller) and children (callees). The nodes also keeps the IDs of all its samples (so no information is lost, just sorted by stack). You get at this through the CallTreeNodeBase.GetSamples method. The caller (parent) of this node The nodes this node calls (its children). Returns true if Callees is empty. AllCallees is an extension of CallTreesNodes to support graphs (e.g. memory heaps). It always starts with the 'normal' Callees, however in addition if we are displaying a Graph, it will also children that were 'pruned' when the graph was transformed into a tree. (by using StackSource.GetRefs). Returns true if AllCallees is non-empty. Returns true if the call trees came from a graph (thus AllCallees may be strictly larger than Callees) Writes an XML representation of the call tree Node it 'writer' Returns an XML representation of the call tree Node (for debugging); Adds up the counts of all nodes called 'BROKEN' nodes in a particular tree node This is a utility function. Creates a string that has spaces | and + signs that represent the indentation level for the tree node. (Called from XAML) Implements CallTreeNodesBase interface Sort the childre of every node in the te Some calltrees already fill in their children, others do so lazily, in which case they override this method. Fold away any nodes having less than 'minInclusiveMetric'. If 'sumByID' is non-null then the only nodes that have a less then the minInclusiveMetric for the whole trace are folded. A CallerCalleeNode gives statistics that focus on a NAME. (unlike calltrees that use ID) It takes all stackSource that have callStacks that include that treeNode and compute the metrics for all the callers and all the callees for that treeNode. Given a complete call tree, and a Name within that call tree to focus on, create a CallerCalleeNode that represents the single Caller-Callee view for that treeNode. The list of CallTreeNodeBase nodes that called the method represented by this CallerCalleeNode The list of CallTreeNodeBase nodes that where called by the method represented by this CallerCalleeNode wrtites an XML representation of the call tree Node it 'writer' Returns an XML representation of the CallerCalleeNode (for debugging); Implements CallTreeNodesBase interface A caller callee view is a summation which centers around one 'focus' node which is represented by the CallerCalleeNode. This node has a caller and callee list, and these nodes (as well as the CallerCalleNode itself) represent the aggregation over the entire tree. AccumulateSamplesForNode is the routine that takes a part of a aggregated call tree (represented by 'treeNode' and adds in the statistics for that call tree into the CallerCalleeNode aggregations (and its caller and callee lists). 'recursionsCount' is the number of times the focus node name has occurred in the path from 'treeNode' to the root. In addition to setting the CallerCalleeNode aggregation, it also returns a 'weightedSummary' inclusive aggregation FOR JUST treeNode (the CallerCalleNode is an aggregation over the entire call tree accumulated so far). The key problem for this routine to avoid is double counting of inclusive samples in the face of recursive functions. Thus all samples are weighted by the recursion count before being included in 'weightedSummaryRet (as well as in the CallerCalleeNode and its Callers and Callees). An important optimization is the ability to NOT create (but rather reuse) CallTreeNodes when returning weightedSummaryRet. To accomplish this the weightedSummaryScaleRet is needed. To get the correct numerical value for weightedSummaryRet, you actually have to scale values by weightedSummaryScaleRet before use. This allows us to represent weights of 0 (subtree has no calls to the focus node), or cases where the subtree is completely uniform in its weighting (the subtree does not contain any additional focus nodes), by simply returning the tree node itself and scaling it by the recursion count). isUniformRet is set to false if anyplace in 'treeNode' does not have the scaling factor weightedSummaryScaleRet. This means the the caller cannot simply scale 'treeNode' by a weight to get weightedSummaryRet. Find the Caller-Callee treeNode in 'elems' with name 'frameName'. Always succeeds because it creates one if necessary. AggregateCallTreeNode supports a multi-level caller-callee view. It does this by allow you to take any 'focus' node (typically a byname node) and compute a tree of its callers and a tree of its callees. You do this by passing the node of interested to either the 'CallerTree' or 'CalleeTrees'. The AggregateCallTreeNode remembers if if is a caller or callee node and its 'Callees' method returns the children (which may in fact be Callers). What is nice about 'AggregateCallTreeNode is that it is lazy, and you only form the part of the tree you actually explore. A classic 'caller-callee' view is simply the caller and callee trees only explored to depth 1. Given any node (typically a byName node, but it works on any node), Create a tree rooted at 'node' that represents the callers of that node. Given any node (typically a byName node, but it works on any node), Create a tree rooted at 'node' that represents the callees of that node. Calls 'callback' for each distinct call tree in this node. Note that the same trees can overlap (in the case of recursive functions), so you need a mechanism for visiting a tree only once. Returns an XML representation of the AggregateCallTreeNode (for debugging); Implementation of CallTreeNodeBase interface Implementation of CallTreeNode interface See m_callerOffset and MergeCallee for more. The 'this' node is a AggregateCallTree representing the 'callers' nodes. Like MergeCallee the aggregate node represents a list of CallTreeNodes. However unlike MergeCallee, the list of CallTreeNodes each represent a sample (a complete call stack) and 'callerOffset' indicates how far 'up' that stack is the node of interest. An aggregateCallTreeNode is exactly that, the sum of several callTrees (each of which represent a number of individual samples). Thus we had to take each sample (which is 'treenode' and merge it into the aggregate. We do this one at a time. Thus we call MergeCallee for each calltree in our list and we find the 'callees' of each of those nodes, and create aggregates for the children (which is in calleeList). This routine is not recursive and does not touch most of the tree but it does call SubtractOutTrees which is recursive and may look at a lot of the tree (although we try to minimize this) Traverse 'treeCallee' and subtract out the inclusive time for any tree that matches 'idToExclude' from the node 'statsRet'. This is needed in AggregateCallTrees because the same trees from the focus node are in the list to aggregate, but are also in the subtree's in various places (and thus are counted twice). We solve this by walking this subtree (in this routine) and subtracting out any nodes that match 'idToExclude'. As an optimization this routine also sets the m_recursion bit 'statsRet' if anywhere in 'treeCallee' we do find an id to exclude. That way in a common case (where there is no instances of 'idToExclude') we don't have to actualy walk the tree the second time (we simply know that there is no adjustment necessary. An AggregateCallTree remembers all its samples by maintaining a list of call trees that actually contain the samples that the Aggregate represents. m_trees hold this. AggregateCallTreeNode can represent either a 'callers' tree or a 'callees' tree. For the 'callers' tree case the node represented by the aggregate does NOT have same ID as the tree in the m_trees list. Instead the aggregate is some node 'up the chain' toward the caller. m_callerOffset keeps track of this (it is the same number for all elements in m_trees). For callee nodes, this number is not needed. Thus we use a illegal value (-1) to represent that fact that the node is a callee node rather than a caller node. exports provided StackSource to a Chromium Trace File format schema: https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/ exports provided StackSource to a https://www.speedscope.app/ format schema: https://www.speedscope.app/file-format-schema.json writes pre-calculated data to SpeedScope format A Histogram is logically an array of floating point values. Often they represent frequency, but it can be some other metric. The X axis can represent different things (time, scenario). It is the HisogramContoller which understands what the X axis is. Histograms know their HistogramController but not the reverse. Often Histograms are sparse (most array elements are zero), so the represnetation is designed to optimzed for this case (an array of non-zero index, value pairs). Create a new histogram. Every histogram needs a controller but these controllers can be shared among many histograms. Add a sample to this histogram. The sample to add. Add an amount to a bucket in this histogram. The amount to add to the bucket. The bucket to add to. Computes this = this + histogram * weight in place (this is updated). The number of buckets in this histogram. The that controls this histogram. Get the metric contained in a bucket. The bucket to retrieve. The metric contained in that bucket. Make a copy of this histogram. An independent copy of this histogram. A string representation (for debugging) Create a histogram that is a copy of another histogram. The histogram to copy. Implementes IEnumerable interface Implementes IEnumerable interface Get an IEnumerable that can be used to enumerate the metrics stored in the buckets of this Histogram. The controller for this histogram. A Histogram is conceputually an array of floating point values. A Histogram Controller contains all the information besides the values themselves need to understand the array of floating point value. There are a lot of Histograms, however they all tend to share the same histogram controller. Thus Histograms know their Histogram controller, but not the reverse. Thus HistogramContoller is a abstract class (we have one for time, and one for scenarios). HistogramControllers are responsible for: - Adding a sample to the histogram for a node (see ) - Converting a histogram to its string representation see () - Managing the size and scale of histograms and their corresponding display strings The scale factor for histograms controlled by this HistogramController. The number of buckets in each histogram controlled by this HistogramController. The number of characters in the display string for histograms controlled by this HistogramController. Buckets are a logial concept, where CharacterCount is a visual concept (how many you can see on the screen right now). The CallTree managed by this HistogramController. Force recalculation of the scale parameter. Add a sample to the histogram for a node. The histogram to add this sample to. Must be controlled by this HistogramController. The sample to add. Overriding classes are responsible for extracting the metric, scaling the metric, determining the appropriate bucket or buckets, and adding the metric to the histogram using . Gets human-readable information about a range of histogram characters. The start character index (inclusive). The end character index (exclusive). The histogram. A string containing information about the contents of that character range. Convert a histogram into its display string. The histogram to convert to a string. A string suitable for GUI display. A utility function that turns an array of floats into a ASCII character graph. A utility function that turns an array of floats into a ASCII character graph. Initialize a new HistogramController. The CallTree that this HistogramController controls. Calculate the scale factor for this histogram. The scale factor for this histogram. Calculates an average scale factor for a histogram. The root histogram to calculate against. A scale factor that will normalize the maximum value to 200%. The scale parameter. 0.0 if uncalculated. An enum representing a displayed histogram bucket (one character in a histogram string). A HistogramCharacterIndex can be used to represent error conditions A that groups histograms by scenarios. Initialize a new ScenarioHistogramController. The CallTree to manage. An ordered array of scenario IDs to display. The total number of possible scenarios that can be supplied by the underlying StackSource. This number might be larger than the highest number in . The names of the scenarios (for UI use). Get a list of scenarios contained in a given bucket. The bucket to look up. The scenarios contained in that bucket. Get a list of scenarios contained in a given bucket range. The start of the bucket range (inclusive). The end of the bucket range (exclusive). The scenarios contained in that range of buckets. Add a sample to a histogram controlled by this HistogramController. The histogram to add the sample to. The sample to add. Get the human-readable name for a scenario. The ID of the scenario to look up. The human-readable name for that scenario. Get the human-readable names for all scenarios contained in a range of histogram characters. The (inclusive) start index of the range. The (exclusive) end index of the range. The histogram. A comma-separated list of scenario names contained in that range. Convert a histogram into a string suitable for UI display. The histogram to convert. A string representing the histogram that is suitable for UI display. Calculate the scale factor for all histograms controlled by this ScenarioHistogramController. In the current implementation, returns a scale that normalizes 100% to half of the maximum value at the root. An array mapping each scenario to a bucket. An array mapping each bucket to a list of scenarios. An array mapping each scenario to its name. A HistogramController holds all the information to understand the buckets of a histogram (basically everything except the array of metrics itself. For time this is the start and end time Create a new TimeHistogramController. The CallTree to control with this controller. The start time of the histogram. The end time of the histogram. The start time of the histogram. The end time of the histogram. Gets the start time for the histogram bucket represented by a character. The index of the character to look up. The start time of the bucket represented by the character. The duration of time represented by each bucket. Implements HistogramController interface Implements HistogramController interface Implements HistogramController interface Implements HistogramController interface The CpuNumber the sample occurred on Copy a LinuxPerfScriptStackSourceSample from 'template' Copy a LinuxPerfScriptStackSourceSample from 'template' Gets a LinuxPerfScriptStackSourceSample The number of times to trampoline to a new thread before assuming infinite recursion and failing the operation. This structure provides a clean API for a lightweight recursion stack guard to prevent StackOverflow exceptions We do ultimately do a stack-overflow to prevent infinite recursion, but it is now under our control and much larger than you may get on any one thread stack. For recursive methods that need to process deep stacks, this constant defines the limit for recursion within a single thread. After reaching this limit, methods need to trampoline to a new thread before continuing to recurse. The amount of recursion we have currently done. Gets the recursion guard for entering a recursive method. This is equivalent to the default value. Gets an updated recursion guard for recursing into a method. Gets an updated recursion guard for continuing execution on a new thread. Gets a value indicating whether the current operation has exceeded the recursion depth for a single thread, and needs to continue executing on a new thread. A stack source is a logically a list of StackSourceSamples. Each sample has a metric and stack (hence the name StackSource) The stacks are represented as indexes that the StackSourceStacks base class can resolve into frame names and stack chains. The result is very efficient (no string processing) way of processing the conceptual list of stack samples. Call 'callback' on every sample in the StackSource. Will be done linearly and only one callback will be active simultaneously. Call 'callback' on every sample in the StackSource. Will be done linearly and only one callback will be active simultaneously. If this is overridden to return true, then during the 'Foeach' callback you can save references to the samples you are given because they will not be overridden by the stack source. If this is false you must make a copy of the sample if you with to remember it. Also called 'callback' on every sample in the StackSource however there may be more than one callback running simultaneously. Thus 'callback' must be thread-safe and the order of the samples should not matter. If desiredParallelism == 0 (the default) then the implementation will choose a good value of parallelism. If this stack source is a source that simply groups another source, get the base source. It will return itself if there is no base source. If this source supports fetching the samples by index, this is how you get it. Like ForEach the sample that is returned is not allowed to be modified. Also the returned sample will become invalid the next time GetSampleIndex is called (we reuse the StackSourceSample on each call) Returns the limit on stack samples indexes (all index are strictly less than this). Returns 0 if unknown. Returns a time which is greater than or equal the timestamp of any sample in the StackSource. Returns 0 if unknown. In addition to Time and Metric a sample can have a Scneario number associated with it. ScenarioCount returns the number of such scnearios. Returning 0 implies no scenario support. StackSources can optionally support a sampling rate. If the source supports it it will return non-null for the current sampling rate (1 if it is doing nothing). Sampling is a way of speeding things up. If you sample at a rate of 10, it means that only one out of every 10 samples is actually produced by 'ForEach'. Note that it is expected that when the sampling rate is set the source will correspondingly adjust the CountMultiplier, so that the total will look like no sampling is occurring If each 'callstack' is really a node in a graph (like MemoryGraphStackSource) Then return true. If this returns true 'GetRefs' works. Only used if IsGraphSource==true. If 'direction' is 'From' Calls 'callback' for node that is referred to FROM nodeIndex. If 'direction' is 'To' then it calls 'callback' for every node that refers TO nodeIndex. This API returns references that are not necessarily a tree (they can for DAGs or have cycles). Dump the stack source to a file as XML. Used for debugging. Dump the stack source to a TextWriter as XML. Used for debugging. RefDirection represents the direction of the references in a heap graph. Indicates that you are interested in referneces FROM the node of interest Indicates that you are interested in referneces TO the node of interest Samples have stacks (lists of frames, each frame contains a name) associated with them. This interface allows you to get at this information. We don't use normal objects to represent these but rather give each stack (and frame) a unique (dense) index. This has a number of advantages over using objects to represent the stack. * Indexes are very serialization friendly, and this data will be presisted. Thus indexes are the natural form for data on disk. * It allows the data to be read from the serialized format (disk) lazily in a very straightfoward fashion, keeping only the hottest elements in memory. * Users of this API can associate additional data with the call stacks or frames trivially and efficiently simply by having an array indexed by the stack or frame index. So effectively a StackSourceStacks is simply a set of 'Get' methods that allow you to look up information given a Stack or frame index. Given a call stack, return the call stack of the caller. This function can return StackSourceCallStackIndex.Discard which means that this sample should be discarded. For efficiency, m_frames are assumed have a integer ID instead of a string name that is unique to the frame. Note that it is expected that GetFrameIndex(x) == GetFrameId(y) then GetFrameName(x) == GetFrameName(y). The converse does NOT have to be true (you can reused the same name for distinct m_frames, however this can be confusing to your users, so be careful. FilterStackSources can combine more than one frame into a given frame. It is useful to know how many times this happened. Returning 0 means no combining happened. This metric does not include grouping, but only folding. Get the frame name from the FrameIndex. If 'verboseName' is true then full module path is included. all StackSourceCallStackIndex are guaranteed to be less than this. Allocate an array of this size to associate side information all StackSourceFrameIndex are guaranteed to be less than this. Allocate an array of this size to associate side information True if it only has managed code stacks. Otherwise false. Computes the depth (number of callers), associated with callStackIndex. This routine is O(n) and mostly useful for debugging. Returns an XML string representation of a 'sample'. For debugging. Returns an XML string representation of a 'callStackIndex'. For debugging. StackSourceSample represents a single sample that has a stack. It has a number of predefined data items associate with it including a stack, a metric and a time as well as other optional fields. Note that all its properties are read-write. It is basically a named tuple. StackSource.ProductSamples push these. In general StackSourceSample are NOT immutable but expected to be overwritted frequently. Thus you need to copy the sample if you want to keep a reference to it. The Stack associated with the sample The metric (cost) associated with the sample If the source supports fetching samples by some ID, then SampleIndex returns this ID for the sample and GetSampleByIndex is the API that converts this index into a sample again. The time associated with the sample. (can be left 0) Normally the count of a sample is 1, however when you take a statistical sample, and you also have other constraints (like you do when you are going a sample of heap memory), you may need to have the count adjusted to something else. A scenario is simply a integer that represents some group the sample belongs to. Returns an XML string representing the sample Returns an XML string representing the sample, howevever this one can actually expand the stack because it is given the source Create a StackSourceSample which is associated with 'source'. Copy a StackSourceSample from 'template' Identifies a particular sample from the sample source, it allows 3rd parties to attach additional information to the sample by creating an array indexed by sampleIndex. Returned when no appropriate Sample exists. An opaque handle that are 1-1 with a complete call stack The first real call stack index (after the pseudo-ones before this) Returned when no appropriate CallStack exists. (Top of stack) Identifies a particular frame within a stack It represents a particular instruction pointer (IP) location in the code or a group of such locations. Pseduo-node representing the root of all stacks Pseduo-frame that represents the caller of all broken stacks. Unknown what to do (Must be before the 'special ones below') // Non negative represents normal m_frames (e.g. names of methods) Profiling overhead (rundown) The first real call stack index (after the pseudo-ones before this) Should not happen (uninitialized) (also means completely folded away) Sample has been filtered out (useful for filtering stack sources) A StackSourceModuleIndex uniquely identifies a module to the stack source. Start is where 'ordinary' module indexes start. Invalid is a module index that is never used and can be used to signal error conditions. This stack source takes another and copies out all its events. This allows you to 'replay' the source efficiently when the original source only does this inefficiently. Create a CopyStackSource that has no samples in it. It can never have samples so it is only useful as a placeholder. Create a CopyStackSource that you can add samples which use indexes that 'sourceStacks' can decode. All samples added to the stack source must only refer to this StackSourceStacks Add a sample to stack source. it will clone 'sample' so sample can be overwritten after this method returns. It is an error if 'sample' does not used the StackSourceStacks passed to the CopyStackSource at construction. Create a clone of the given stack soruce. Returns the StackSourceStacks that can interpret indexes for this stack source. Implementation of the StackSource interface Implementation of the StackSource interface Implementation of the StackSource interface Implementation of the StackSource interface Implementation of the StackSource interface Implementation of the StackSource interface Implementation of the StackSource interface Implementation of the StackSource interface Implementation of the StackSource interface Implementation of the StackSource interface Like CopyStackSource InternStackSource copies the samples. however unlike CopyStackSource InternStackSource copies all the information in the stacks too (mapping stack indexes to names) Thus it never refers to the original source again). It also interns the stacks making for an efficient representation of the data. This is useful when the original source is expensive to iterate over. Compute the difference between two sources of stacks. Compute only the delta of source from the baseline. This variation allows you to specify the unfiltered names (the sourceStacks and baselineStacks) but otherwise keep the filtering. Create a new stack source that can create things out of nothing. Create a new InternStackSource Returns the Interner, which is the class that holds the name->index mappings that that every name has a unique index. Implementation of the StackSource interface Implementation of the StackSource interface Implementation of the StackSource interface Implementation of the StackSource interface Implementation of the StackSource interface InternFullStackFromSource will take a call stack 'baseCallStackIndex' from the source 'source' and completely copy it into the intern stack source (interning along the way of course). Logically baseCallStackIndex has NOTHING to do with any of the call stack indexes in the intern stack source. StackSourceInterner is a helper class that knows how to intern module, frame and call stacks. Create a new StackSourceInterner. Optionally supply estimates on how many items you need and where the frame, callstack and module indexes start. As an optimization, if you are done adding new nodes, then you can call this routine can abandon some tables only needed during the interning phase. The CallStackStartIndex value passed to the constructor The FrameStartIndex value passed to the constructor Given a StackSourceCallStackIndex return the StackSourceCallStackIndex of the caller Given a StackSourceCallStackIndex return the StackSourceFrameIndex for the Frame associated with the top call stack Get a name from a frame index. If the frame index is a Given a StackSourceFrameIndex return the StackSourceModuleIndex associated with the frame If you intern frames as derived frames, when GetFrameName is called the interner needs to know how to look up the derived frame from its index. This is the function that is called. It is called with the frame index and a boolean which indicates whether the full path of the module should be specified, and returns the frame string. Lookup or create a StackSourceModuleIndex for moduleName Lookup or create a StackSourceFrameIndex for frame with the name frameName and the module identified by moduleIndex You can also create frames out of other frames using this method. Given an existing frame, and a suffix 'frameSuffix' Lookup or create a StackSourceCallStackIndex for a call stack with the frame identified frameIndex and caller identified by callerIndex The current number of unique frames that have been interned so far The current number of unique call stacks that have been interned so far A specialized hash table for interning. It loosely follows the implementation of but with several key allowances for known usage patterns: 1. We don't store the hashcode on each entry on the assumption that values can be compared as quickly as recomputing hash codes. The downside to that is that the hash codes must be recomputed whenever the map is resized, but that is very cheap. 2. We supply a single method (instead of a TryGetValue followed by an Add) so that a hashcode computation is saved in the case of a "miss". 3. We don't support removal. This means we don't need to keep track of a free list and neither do we need sentinel values. This also allows us to use all 32 bits of the hash-code (where uses only 31 bits, reserving -1 to indicate a freed entry. The only sentinel value is in the array to indicate a free bucket. 4. We return an index (of the interned item) to the caller which can be used for constant-time look-up in the table via . 5. To free up memory, the caller can call . The entries themselves are stored separately from the indexing parts of the table so that the latter can be dropped easily. Construct the intern map The estimated capacity of the map. Count of interned values. Access an element by index. The zero-based index of the desired entry. The entry at the requested index. For performance, in Release mode we do no range checking on , so it is possible to access an entry beyond but prior to the maximum capacity of the array. was less than zero or greater than the capacity. Intern a value. If the same value has been seen before then this returns the index of the previously seen entry. If not, a new entry is added and this returns the index of the newly added entry. The candidate value. The index of the interned entry. This routine was called after calling . As an optimization, if you are done calling , then you can call this to free up some memory. After calling this, you can still call . However, if you try to call you will get a . Elements representing the structure of the hash table. The structure is a collection of singly linked lists, one list per 'bucket' where a bucket number is selected by taking the hash code of an incoming item and mapping it onto the array (see ). Caution: For a given , and are UNRELATED to each other. Logically, you can think of as being part of a value in the table. (We don't actually do that in order to support efficiently.) To find the next element in the linked list, you should NOT simply look at . Instead, you should first look up the in the array indexed by and look at the field of that. Index into the array of the head item in the linked list or -1 to indicate an empty bucket. Index into the array of the next item in the linked list or -1 to indicate that this is the last item. we want to identify the thread for every sample to prevent from overlaping of samples for the concurrent code so we group the samples by Threads this method also sorts the samples by relative time (ascending) all the samples that we have are leafs (last sample in the call stack) this method walks the stack up to the beginning and merges the samples and outputs them in proper order this method checks if both samples do NOT belong to the same profile event TraceEventStackSource is an implementation of a StackSource for ETW information (TraceLog) It takes a TraceEvents (which is a list of TraceEvents you get get from a TraceLog) and implements that StackSource protocol for them. (thus any code needing a StackSource can then work on it. The key to the implementation is how StackSourceFrameIndex and StackSourceCallStackIndex (part of the StackSource protocol) are mapped to the Indexes in TraceLog. Here is the mapping. TraceEventStackSource create the following meaning for the StackSourceCallStackIndex * The call stacks ID consists of the following ranges concatenated together. * a small set of fixed Pseudo stacks (Start marks the end of these) * CallStackIndex * ThreadIndex * ProcessIndex * BrokenStacks (One per thread) * Stacks for CPU samples without explicit stacks (we make 1 element stacks out of them) TraceEventStackSource create the following meaning for the StackSourceFrameIndex The frame ID consists of the following ranges concatenated together. * a small fixed number of Pseudo frame (Broken, and Unknown) * MaxCodeAddressIndex - something with a TraceCodeAddress. * ThreadIndex - ETW stacks don't have a thread or process node, so we add them. * ProcessIndex Creates a new TraceEventStackSource given a list of events 'events' from a TraceLog Returns the TraceLog file that is associated with this stack source. Normally addresses without symbolic names are listed as ?, however sometimes it is useful to see the actual address as a hexadecimal number. Setting this will do that. Displays the optimization tier of each code version executed for the method. Looks up symbols for all modules that have an inclusive count >= minCount. stackSource, if given, can be used to be the filter. If null, 'this' is used. If stackSource is given, it needs to use the same indexes for frames as 'this'. shouldLoadSymbols, if given, can be used to filter the modules. Given a frame index, return the corresponding code address for it. This is useful for looking up line number information. Implementation of StackSource protocol. Implementation of StackSource protocol. Implementation of StackSource protocol. Implementation of StackSource protocol. Implementation of StackSource protocol. Implementation of StackSource protocol. Implementation of StackSource protocol. Implementation of StackSource protocol. Returns a list of modules for the stack 'stackIdx'. It also updates the interning table stackModuleLists, so that the entry cooresponding to stackIdx remembers the answer. This can speed up processing a lot since many stacks have the same prefixes to root. A ModuleList is a linked list of modules. It is only used in GetModulesForStack and LookupWarmSymbols This maps pseudo-stacks to their index (thus it is the inverse of m_pseudoStack; Given a thread and a call stack that does not have a stack, make up a pseudo stack for it consisting of the code address, the broken node, the thread and process. Will return -1 if it can't allocate another Pseudo-stack. Like a TraceEventStackSource a MutableTraceEventStackSource allows you incorporate the stacks associated with a TraceEvent as a sample in the StackSource. However in addition it allows you to create new frames for these stacks on the fly as well as add samples that did not exist in the original TraceEvent stream. This gives you a lot of flexibility to add additional data to the original stream of TraceEvents. Like TraceEventStackSource MutableTraceEventStackSource supports the GetFrameCodeAddress() method that allows you to map from the StackSourceFrameIndex back its TraceLog code address (that lets you get at the source code and line number for that frame). Create a new MutableTraceEventStackSource that can represent stacks coming from any events in the given TraceLog with a stack. You use the 'AddSample' and 'DoneAddingSamples' to specify exactly which stacks you want in your source. After creating a MultableTraceEventStackSource, you add the samples you want using this AddSample API (you can reuse 'sample' used as an argument to this routine. It makes a copy. The samples do NOT need to be added in time order (the MultableTraceEventStackSource will sort them). When you done DoneAddingSamples must be called before using the the MutableTraceEventStackSource as a stack source. After calling 'AddSample' to add the samples that should belong to the source, DoneAddingSamples() should be called to to complete the construction of the stack source. Only then can the reading API associated with the stack source be called. The Interner is the class that allows you to make new indexes out of strings and other bits. Returns a StackSourceCallStackIndex representing just one entry that represents the process 'process' Returns a StackSourceCallStackIndex representing just two entries that represent 'thread' which has a parent of its process. Returns a StackSourceCallStackIndex representing the call stack from the TraceLog represented by the CallStackIndex 'callStackIndex'. If that stack is invalid, use 'thread' to at least return a call stack for the thread. Returns a StackSourceCallStackIndex representing the call stack from the TraceLog represented by the CallStackIndex 'callStackIndex'. Use the TraceEvent 'data' to find the stack if callStackIndex is invalid. TODO data should be removed (or callstack derived from it) A very simple IDictionary-like interface for remembering values in GetCallStack() Fetches an value given a key Sets a key-value pair Find the StackSourceCallStackIndex for the TraceEvent call stack index 'callStackIndex' which has a top of its stack (above the stack, where the thread and process would normally go) as 'top'. If callStackMap is non-null it is used as an interning table for CallStackIndex -> StackSourceCallStackIndex. This can speed up the transformation dramatically. It will still work if it is null. Create a frame name from a TraceLog code address. Implementation of StackSource protocol. Implementation of StackSource protocol. Implementation of StackSource protocol. Implementation of StackSource protocol. Implementation of StackSource protocol. Implementation of StackSource protocol. Implementation of StackSource protocol. Implementation of StackSource protocol. Implementation of StackSource protocol. Implementation of StackSource protocol. Implementation of StackSource protocol. private private TraceEventSource is an abstract base class that represents the output of a ETW session (e.g. a ETL file or ETLX file or a real time stream). This base class is NOT responsible for actually processing the events, but contains methods for properties associated with the session like its start and end time, filename, and characteristics of the machine it was collected on. This class has two main subclasses: * which implements a 'push' (callback) model and is the only mode for ETL files. ETWTraceEventSource is the most interesting subclass of TraceEventDispatcher. * see TraceLog which implements both a 'push' (callback) as well as pull (foreach) model but only works on ETLX files. This is the end. The normal user pattern is to create a TraceEventSource, create TraceEventParsers attached to the TraceEventSource, and then subscribe event callbacks using the TraceEventParsers For convenience, we provide a property returns a ClrTraceEventParser that knows how to parse all the Common Language Runtime (CLR .NET) events into callbacks. For convenience, we provide a property returns a KernelTraceEventParser that knows how to parse all the Kernel events into callbacks. For convenience, we provide a property returns a DynamicTraceEventParser that knows how to parse all event providers that dynamically log their schemas into the event streams. In particular, it knows how to parse any events from a System.Diagnostics.Tracing.EventSources. Note that the DynamicTraceEventParser has subsumed the functionality of RegisteredTraceEventParser so any registered providers are also looked up here. For convenience, we provide a property returns a RegisteredTraceEventParser that knows how to parse all providers that are registered with the operating system. Because the DynamicTraceEventParser has will parse all providers that that RegisteredTraceEventParser will parse, this function is obsolete, you should use Dynamic instead. The time when session started logging. The time that the session stopped logging. The Session End time expressed as milliseconds from the start of the session The difference between SessionEndTime and SessionStartTime; The size of the trace, if it is known. Will return 0 if it is not known. Returns the size of a pointer on the machine where events were collected (4 for 32 bit or 8 for 64 bit) The number of events that were dropped (e.g. because the incoming event rate was too fast) The number of processors on the machine doing the logging. Cpu speed of the machine doing the logging. The version of the windows operating system on the machine doing the logging. Returns true if this is a real time session. Time based threshold for how long data should be retained by accumulates that are processing this TraceEventSource. A value of 0, the default, indicates an infinite accumulation. Check if a DataLifetime model is enabled True - lifetime tracking is enabled False - lifetime tracking is not enabled Closes any files and cleans up any resources associated with this TraceEventSource TraceEventSource supports attaching arbitrary user data to the source. This property returns a key-value bag of these attached values. One convention that has been established is that TraceEventParsers that need additional state to parse their events should store them in UserData under the key 'parsers\(ParserName)' Dispose pattern This is the high frequency tick clock on the processor (what QueryPerformanceCounter uses). You should not need Converts the Query Performance Counter (QPC) ticks to a number of milliseconds from the start of the trace. Converts a Relative MSec time to the Query Performance Counter (QPC) ticks Converts a DateTime to the Query Performance Counter (QPC) ticks Converts the Query Performance Counter (QPC) ticks to a DateTime Some events (like HardFault) do not have a thread ID or a process ID, but they MIGHT have a Stack If they do try to get the ThreadID for the event from that. Return -1 if not successful. This is intended to be overridden by the TraceLog class that has this additional information. TraceEvent an abstract class represents the data from one event in the stream of events in a TraceEventSource. The TraceEvent class has all the properties of an event that are common to all ETW events, including TimeStamp ProviderGuid, ProcessID etc. Subclasses of TraceEvent then extend this abstract class to include properties specific to a particular payload. An important architectural point is that TraceEvent classes are aggressively reused by default. The TraceEvent that is passed to any TraceEventParser callback or in a foreach is ONLY valid for the duration for that callback (or one iteration of the foreach). If you need save a copy of the event data, you must call the Clone() method to make a copy. The IObservable interfaces (TraceEventParser.Observe* methods) however implicitly call Clone() so you do not have to call Clone() when processing with IObservables (but these are slower). The GUID that uniquely identifies the Provider for this event. This can return Guid.Empty for classic (Pre-VISTA) ETW providers. Unique GUID for Pre-VISTA ETW providers. The name of the provider associated with the event. It may be of the form Provider(GUID) or UnknownProvider in some cases but is never null. A name for the event. This is simply the concatenation of the task and opcode names (separated by a /). If the event has no opcode, then the event name is just the task name. Returns the provider-specific integer value that uniquely identifies event within the scope of the provider. (Returns 0 for classic (Pre-VISTA) ETW providers). Events for a given provider can be given a group identifier (integer) called a Task that indicates the broad area within the provider that the event pertains to (for example the Kernel provider has Tasks for Process, Threads, etc). The human readable name for the event's task (group of related events) (eg. process, thread, image, GC, ...). May return a string Task(GUID) or Task(TASK_NUM) if no good symbolic name is available. It never returns null. An opcode is a numeric identifier (integer) that identifies the particular event within the group of events identified by the event's task. Often events have opcode 'Info' (0), which is the default. This value is interpreted as having no-opcode (the task is sufficient to identify the event). Generally the most useful opcodes are the Start and Stop opcodes which are used to indicate the beginning and the end of a interval of time. Many tools will match up start and stop opcodes automatically and compute durations. Returns the human-readable string name for the Opcode property. The verbosity of the event (Fatal, Error, ..., Info, Verbose) The version number for this event. The only compatible change to an event is to add new properties at the end. When this is done the version numbers is incremented. ETW Event providers can specify a 64 bit bitfield called 'keywords' that define provider-specific groups of events which can be enabled and disabled independently. Each event is given a keywords mask that identifies which groups the event belongs to. This property returns this mask. A Channel is a identifier (integer) that defines an 'audience' for the event (admin, operational, ...). Channels are only used for Windows Event Log integration. The time of the event. You may find TimeStampRelativeMSec more convenient. Returns a double representing the number of milliseconds since the beginning of the session. The thread ID for the thread that logged the event This field may return -1 for some events when the thread ID is not known. The process ID of the process which logged the event. This field may return -1 for some events when the process ID is not known. Returns a short name for the process. This the image file name (without the path or extension), or if that is not present, then the string 'Process(XXXX)' The processor Number (from 0 to TraceEventSource.NumberOfProcessors) that logged this event. event. Get the size of a pointer associated with process that logged the event (thus it is 4 for a 32 bit process). Conceptually every ETW event can be given a ActivityID (GUID) that uniquely identifies the logical work being carried out (the activity). This property returns this GUID. Can return Guid.Empty if the thread logging the event has no activity ID associated with it. ETW supports the ability to take events with another GUID called the related activity that is either causes or is caused by the current activity. This property returns that GUID (or Guid.Empty if the event has not related activity. Event Providers can define a 'message' for each event that are meant for human consumption. FormattedMessage returns this string with the values of the payload filled in at the appropriate places. It will return null if the event provider did not define a 'message' for this event Creates and returns the value of the 'message' for the event with payload values substituted. Payload values are formatted using the given formatProvider. An EventIndex is a integer that is guaranteed to be unique for this event over the entire log. Its primary purpose is to act as a key that allows side tables to be built up that allow value added processing to 'attach' additional data to this particular event unambiguously. This property is only set for ETLX file. For ETL or real time streams it returns 0 EventIndex is currently a 4 byte quantity. This does limit this property to 4Gig of events The TraceEventSource associated with this event. Returns true if this event is from a Classic (Pre-VISTA) provider The ID of the container that emitted the event, if available. Returns the names of all the manifest declared field names for the event. May be empty if the manifest is not available. Given an index from 0 to PayloadNames.Length-1, return the value for that payload item as an object (boxed if necessary). PayloadString is like PayloadValue(index).ToString(), however it can do a better job in some cases. In particular if the payload is a enumeration or a bitfield and the manifest defined the enumeration values, then it will print the string name of the enumeration value instead of the integer value. Returns the index in 'PayloadNames for field 'propertyName'. Returns something less than 0 if not found. PayloadByName fetches the value of a payload property by the name of the property. It will return null if propertyName is not found. This method is not intended to be used in performance critical code. PayloadStringByName functions the same as PayloadByName, but uses PayloadString instead of PayloadValue. It will return null if propertyName is not found. This method is not intended to be used in performance critical code. The size of the event-specific data payload. (see EventData) Normally this property is not used because some TraceEventParser has built a subclass of TraceEvent that parses the payload Returns an array of bytes representing the event-specific payload associated with the event. Normally this method is not used because some TraceEventParser has built a subclass of TraceEvent that parses the payload Gets the event data and puts it in 'targetBuffer' at 'targetStartIndex' and returns the resulting buffer. If 'targetBuffer is null, it will allocate a buffer of the correct size. Normally this method is not used because some TraceEventParser has built a subclass of TraceEvent that parses the payload The events passed to the callback functions only last as long as the callback, so if you need to keep the information around after that you need to copy it. This method makes that copy. This method is more expensive than copy out all the event data from the TraceEvent instance to a type of your construction. Pretty print the event. It uses XML syntax.. Pretty print the event using XML syntax, formatting data using the supplied IFormatProvider Write an XML representation to the stringBuilder sb and return it. Writes an XML representation of the event to a StringBuilder sb, formatting data using the passed format provider. Returns the StringBuilder. Dumps a very verbose description of the event, including a dump of they payload bytes. It is in XML format. This is very useful in debugging (put it in a watch window) when parsers are not interpreting payloads properly. EventTypeUserData is a field users get to use to attach their own data on a per-event-type basis. Returns the raw IntPtr pointer to the data blob associated with the event. This is the way the subclasses of TraceEvent get at the data to display it in a efficient (but unsafe) manner. Create a template with the given event meta-data. Used by TraceParserGen. Skip UTF8 string starting at 'offset' bytes into the payload blob. Offset just after the string Skip Unicode string starting at 'offset' bytes into the payload blob. Offset just after the string Skip 'stringCount' Unicode strings starting at 'offset' bytes into the payload blob. Offset just after the last string Skip a Security ID (SID) starting at 'offset' bytes into the payload blob. Offset just after the Security ID Trivial helper that allows you to get the Offset of a field independent of 32 vs 64 bit pointer size. The Offset as it would be on a 32 bit system The number of pointer-sized fields that came before this field. Computes the size of 'numPointers' pointers on the machine where the event was collected. Given an Offset to a null terminated ASCII string in an event blob, return the string that is held there. Returns the string represented by a fixed length ASCII string starting at 'offset' of length 'charCount' Given an Offset to a fixed sized string at 'offset', whose buffer size is 'charCount' Returns the string value. A null in the string will terminate the string before the end of the buffer. Returns the encoding of a Version 6 IP address that has been serialized at 'offset' in the payload bytes. Returns the GUID serialized at 'offset' in the payload bytes. Get the DateTime that serialized (as a windows FILETIME) at 'offset' in the payload bytes. Given an Offset to a null terminated Unicode string in an payload bytes, return the string that is held there. Give an offset to a byte array of size 'size' in the payload bytes, return a byte[] that contains those bytes. Returns a byte value that was serialized at 'offset' in the payload bytes Returns a short value that was serialized at 'offset' in the payload bytes Returns an int value that was serialized at 'offset' in the payload bytes Returns a long value that was serialized at 'offset' in the payload bytes Get something that is machine word sized for the provider that collected the data, but is an integer (and not an address) Gets something that is pointer sized for the provider that collected the data. Returns an int float (single) that was serialized at 'offset' in the payload bytes Returns an int double precision floating point value that was serialized at 'offset' in the payload bytes Write the XML attribute 'attribName' with value 'value' to the string builder Write the XML attribute 'attribName' with value 'value' to the string builder Write the XML attribute 'attribName' with value 'value' to the string builder Write the XML attribute 'attribName' with value 'value' to the string builder Write the XML attribute 'attribName' with value 'value' to the string builder Write the XML attribute 'attribName' with value 'value' to the string builder Write the XML attribute 'attribName' with value 'value' to the string builder Write the XML attribute 'attribName' with value 'value' to the string builder Prints a standard prefix for a event (includes the time of the event, the process ID and the thread ID. Because we want the ThreadID to be the ID of the CREATED thread, and the stack associated with the event is the parentThreadID Returns (or sets) the delegate associated with this event. If this TraceEvent belongs to a parser that needs state, then this callback will set the state. Parsers with state are reasonably rare, the main examples are KernelTraceEventParser and ClrTraceEventParser. Returns the Timestamp for the event using Query Performance Counter (QPC) ticks. The start time for the QPC tick counter is arbitrary and the units also vary. A standard way for events to are that certain addresses are addresses in code and ideally have symbolic information associated with them. Returns true if successful. Was this written with the windows EventWriteString API? (see also EventDataAsString) Used for binary searching of event IDs. Abstracts the size (currently a int, could go to long) Returns true if the two traceEvents have the same identity. Normally TraceEvent does not have unmanaged data, but if you call 'Clone' it will. For debugging. dumps an array. If you specify a size of 0 (the default) it dumps the whole array. If the event data looks like a unicode string, then return it. This is heuristic. (See also IsEventWriteString) Each TraceEvent items knows where it should Dispatch to. ETWTraceEventSource.Dispatch calls this function to go to the right placed. By default we do nothing. Typically a subclass just dispatches to another callback that passes itself to a type-specific event callback. This is a DEBUG-ONLY routine that allows a routine to do consistency checking in a debug build. Validate that the events is not trash. TraceEvent knows where to dispatch to. To support many subscriptions to the same event we chain them. The array of names for each property in the payload (in order). Individual event providers can supply many different types of events. These are distinguished from each other by a TraceEventID, which is just a 16 bit number. Its meaning is provider-specific. Illegal is a EventID that is not used by a normal event. Providers can define different audiences or Channels for an event (eg Admin, Developer ...). It is only used for Windows Event log support. The default channel. There are certain classes of events (like start and stop) which are common across a broad variety of event providers for which it is useful to treat uniformly (for example, determining the elapsed time between a start and stop event). To facilitate this, event can have opcode which defines these common operations. Below are the standard ones but providers can define additional ones. Generic opcode that does not have specific semantics associated with it. The entity (process, thread, ...) is starting The entity (process, thread, ...) is stoping (ending) The entity (process, thread, ...) did not terminate before data collection ended, so indicate this at data collection termination time. The entity (process, thread, ...) did not terminate before data collection ended, so indicate this at data collection termination time. This is mostly for 'flight recorder' scenarios where you only have the 'tail' of the data and would like to know about everything that existed. Reserved Reserved Reserved Reserved Reserved Indicates to a provider whether verbose events should be logged. Always log the event (It also can mean that the provider decides the verbosity) You probably should not use it.... Events that indicate critical conditions Events that indicate error conditions Events that indicate warning conditions Events that indicate information Events that verbose information ETW defines the concept of a Keyword, which is a 64 bit bitfield. Each bit in the bitfield represents some provider defined 'area' that is useful for filtering. When processing the events, it is then possible to filter based on whether various bits in the bitfield are set. There are some standard keywords, but most are provider specific. No event groups (keywords) selected All event groups (keywords) selected Tasks are groups of related events for a given provider (for example Process, or Thread, Kernel Provider). They are defined by the provider. If you don't explicitly choose a task you get the default EventIdex is a unsigned integer that is unique to a particular event. EventIndex is guaranteed to be unique over the whole log. It is only used by ETLX files. Currently the event ID simply the index in the log file of the event. We don't however guarantee ordering. In the future we may add new events to the log and given them IDs 'at the end' even if the events are not at the end chronologically. EventIndex is a 32 bit number limits it to 4Gig events in an ETLX file. Invalid is an EventIndex that will not be used by a normal event. TraceEventSource has two roles. The first is the obvious one of providing some properties like 'SessionStartTime' for clients. The other role is provide an interface for TraceEventParsers to 'hook' to so that events can be decoded. ITraceParserServices is the API service for this second role. It provides the methods that parsers register templates for subclasses of the TraceEvent class that know how to parse particular events. RegisterEventTemplate is the mechanism a particular event payload description 'template' (a subclass of TraceEvent) is injected into the event processing stream. Once registered, an event is 'parsed' simply by setting the 'rawData' field in the event. It is up to the template then to take this raw data an present it in a useful way to the user (via properties). Note that parsing is thus 'lazy' in no processing of the raw data is not done at event dispatch time but only when the properties of an event are accessed. Ownership of the template transfers when this call is made. The source will modify this and assumes it has exclusive use (thus you should clone the template if necessary). Another important aspect is that templates are reused by TraceEventSource aggressively. The expectation is that no memory needs to be allocated during a normal dispatch UnregisterEventTemplate undoes the action of RegisterEventTemplate. Logically you would pass the template to unregister, but typically you don't have that at unregistration time. To avoid forcing clients to remember the templates they registered, UnregisterEventTemplate takes three things that will uniquely identify the template to unregister. These are the eventID, and provider ID and the Action (callback) for the template. It is expected that when a subclass of TraceEventParser is created, it calls this method on the source. This allows the source to do any Parser-specific initialization. Indicates that this callback should be called on any unhandled event. The callback returns true if the lookup should be retried after calling this (that is there is the unhandled event was found). Looks if any provider has registered an event with task with 'taskGuid'. Will return null if there is no registered event. Looks if any provider has registered with the given GUID OR has registered any task that matches the GUID. Will return null if there is no registered event. TraceEventParser Represents a class that knows how to decode particular set of events (typically all the events of a single ETW provider). It is expected that subclasses of TraceEventParser have a constructor that takes a TraceEventSource as an argument that 'attaches' th parser to the TraceEventSource. TraceEventParsers break into two groups. * Those that work on a single provider, and thus the provider name is implicit in th parser. This is the common case. The AddCallbackForEvent* methods are meant to be used for these TraceEventParsers * Those that work on multiple providers. There are only a handful of these (DynamicTraceEventParser, ...). The AddCallbackForProviderEvent* methods which take 'Provider' parameters are meant to be used for these TraceEventParsers In addition to the AddCallback* methods on TraceEventParser, there are also Observe* extension methods that provide callbacks using the IObservable style. Get the source this TraceEventParser is attached to. Subscribe to all the events this parser can parse. It is shorthand for AddCallback{TraceEvent}(value)/RemoveCallback(value) A shortcut that adds 'callback' in the provider associated with this parser (ProvderName) and an event name 'eventName'. 'eventName' can be null in which case any event that matches 'Action{T}' will call the callback. 'eventName is of the form 'TaskName/OpcodeName' if the event has a non-trivial opcode, otherwise it is 'TaskName'. The callback alone is used as the subscription id for unregistration, so the callback delegate should be unique (by delegate comparison) Causes 'callback' to be called for any event in the provider associated with this parser (ProviderName) whose type is compatible with T and whose eventName will pass 'eventNameFilter'. Causes 'callback' to be called for any event in the provider associated with this parser (ProviderName) whose type is compatible with T and whose eventName will pass 'eventNameFilter'. The eventNameFilter parameter can be null, in which case all events that are compatible with T will be selected. eventNames passed to the filer are of the form 'TaskName/OpcodeName' if the event has a non-trivial opcode, otherwise it is 'TaskName'. Causes 'callback' to be called for any event in the provider associated with this parser (ProviderName) whose type is compatible with T and whose eventName will pass 'eventNameFilter'. The eventNameFilter parameter can be null, in which case all events that are compatible with T will be selected. A 'subscriptionID' can be passed and this value along with the callback can be used to uniquely identify subscription to remove using the 'RemoveCallback' API. If null is passed, then only the identity of the callback can be used to identify the subscription to remove. eventNames passed to the filer are of the form 'TaskName/OpcodeName' if the event has a non-trivial opcode, otherwise it is 'TaskName'. A shortcut that adds 'callback' for the event in 'providerName' and an event name 'eventName' The callback alone is used as the subscription id for unregistration, so the callback delegate should be unique (by delegate comparison) eventName is of the of the form 'TaskName/OpcodeName' if the event has a non-trivial opcode, otherwise it is 'TaskName'. Cause 'callback' to be called for any event that this parser recognizes for which the function 'eventsToObserve' returns 'AcceptEvent'. The 'eventsToObserve is given both the provider name (first) and the event name and can return 'AcceptEvent' 'RejectEvent' or 'RejectProvider' (in which case it may not be called again for that provider). eventsToObserver can be null in which case all events that match the parser recognizes are selected. eventNames passed to the filer are of the form 'TaskName/OpcodeName' if the event has a non-trivial opcode, otherwise it is 'TaskName'. Thus this method works for parsers that parse more than one provider (e.g. DynamicTraceEventParser). Cause 'callback' to be called for any event that this parser recognizes for which the function 'eventsToObserve' returns 'AcceptEvent'. The 'eventsToObserve is given both the provider name (first) and the event name and can return 'AcceptEvent' 'RejectEvent' or 'RejectProvider' (in which case it may not be called again for that provider). eventsToObserver can be null in which case all events that match the parser recognizes are selected. eventNames passed to the filer are of the form 'TaskName/OpcodeName' if the event has a non-trivial opcode, otherwise it is 'TaskName'. /// Thus this method works for parsers that parse more than one provider (e.g. DynamicTraceEventParser). A subscriptionID can optionally be passed. This is used (along with the callback identity) to identify this to the 'RemoveCallback' If you don't need to remove the callback or you will do it in bulk, you don't need this parameter. Remove all subscriptions added with 'AddCallback' (any overload), that is compatible with T, has a callback 'callback' and subscriptionId 'subscriptionId' where 'subscriptionId' was the value that was optionally passed to 'AddCallback' to provide exactly this disambiguation. 'callback' or 'subscriptionId' can be null, in which case it acts as a wild card. Thus RemoveCallback{TraceEvent}(null, null) will remove all callbacks that were registered through this parser. A static TraceEventParser is a parser where the set of events that can be subscribed to (and their payload fields) are known at compile time. There are very few dynamic TraceEventParsers (DynamicTraceEventParser, RegisteredTraceEventParser and WPPTraceEventParser) All TraceEventParsers invoke this constructor. If 'dontRegister' is true it is not registered with the source. Normally a TraceEvent parser knows how to parse only one provider. If this is true ProviderName returns the name of this provider. If the parser knows how to parse more than one provider, this property returns null. If the parser needs to persist data along with the events we put it in a separate object. This object and then implement serialization functionality that allows it to be persisted (this is for ETLX support). Returns a list of all templates currently existing (new ones can come in, but OnNewEventDefintion must be called whenever that happens. Note that the returned templates MUST be cloned and do not have their source or parser state fields set. These must be set as part of subscription (after you know if you care about them or not). eventsToObserver is given the provider name and event name and those events that return AcceptEvent will have the 'callback' function called on that template. eventsToObserver can be null which mean all events. The returned template IS READ ONLY! If you need a read-write copy (typical), clone it first. If the parser can change over time (it can add new definitions), It needs to support this interface. See EnumerateDynamicTemplates for details. This function should be called any time a new event is now parsable by the parser. If it is guaranteed that the particular event is definitely being ADDED (it never existed in the past), then you can set 'mayHaveExistedBefore' to false and save some time. It returns false if there are no definitions for that particular Provider (and thus you can skip callback if desired). Given a subscription request, and a template that can now be parsed (and its state, which is just TraceEventParser.StateObj) If subscription states that the template should be registered with the source, then do the registration. if 'mayHaveExistedBefore' means that this template definition may have been seen before (DynamicTraceEventParsers do this as you may get newer versions dynamically registering themselves). In that case this should be set. If you can guaranteed that a particular template (provider-eventID pair) will only be subscribed at most once you can set this to false. Keeps track of a single 'AddCallback' request so it can be removed later. It also handles lazy addition of events. Create a subscription request. 'eventsToObserve takes a provider name (first) and a event name and returns a three valued EventFilterResponse value (accept, reject, reject provider) The source that this parser is connected to. EventFilterResponse is the set of responses a user-defined filtering routine, might return. This is used in the TraceEventParser.AddCallbackForProviderEvents method. Not an interesting event, but other events in the same provider may be No event in the provider will be accepted An interesting event An options class for the TraceEventDispatcher StartTime from which you want to start analyzing the events for file formats that support this. EndTime till when you want to analyze events for file formats that support this. A TraceEventDispatcher is a TraceEventSource that supports a callback model for dispatching events. Obtains the correct TraceEventDispatcher for the given trace file name. A path to a trace file. A TraceEventDispatcher for the given trace file. Subscribers to UnhandledEvent are called if no other hander has processed the event. It is generally used in DEBUG builds to validate that events are getting to the source at all. Subscribers to EveryEvent are called on every event in the trace. Normally you don't want to subscribe to this but rather use a TraceEvenParser (which knows how to decode the payloads) and subscribe to particular events through that. For example Using TraceEventSource.Dynamic.All or TraceEventSource.Dynamic.All is more likely to be what you are looking for. AllEvents is only an event callback of last resort, that only gives you the 'raw' data (common fields but no payload). This is called AFTER any event-specific handlers. Subscribers to UnhandledEvent are called if no other hander has processed the event. It is generally used in DEBUG builds to validate that events are getting to the source at all. Subscribers to EveryEvent are called on every event in the trace. Normally you don't want to subscribe to this but rather use a TraceEvenParser and subscribe to particular events through that. This is called AFTER any event-specific handlers. Once a client has subscribed to the events of interest, calling Process actually causes the callbacks to happen. Subclasses implementing this method should call 'OnCompleted' before returning. false If StopProcessing was called Calling StopProcessing in a callback when 'Process()' is running will indicate that processing should be stopped immediately and that the Process() method should return. Note that this stop request will not be honored until the next event from the source. Thus for real time sessions there is an indeterminate delay before the stop will complete. If you need to force the stop you should instead call Dispose() on the session associated with the real time session. This will cause the source to be shut down and thus also stop processing (Process() will return) but is guaranteed to complete in a timely manner. Subscribers of Completed will be called after processing is complete (right before TraceEventDispatcher.Process returns. Wrap (or filter) the dispatch of every event from the TraceEventDispatcher stream. Instead of calling the normal code it calls 'hook' with both the event to be dispatched and the method the would normally do the processing. Thus the routine has the option to call normal processing, surround it with things like a lock or skip it entirely. This can be called more than once, in which case the last hook method gets called first (which may end up calling the second ...) For example,here is an example that uses AddDispatchHook to take a lock is taken whenever dispatch work is being performed. AddDispatchHook((anEvent, dispatcher) => { lock (this) { dispatcher(anEvent); } }); Called when processing is complete. You can call this more than once if your not sure if it has already been called. however we do guard against races. Number of different events that have callbacks associated with them Total number of callbacks that are registered. Even if they are for the same event. This is the routine that is called back when any event arrives. Basically it looks up the GUID and the opcode associated with the event and finds right subclass of TraceEvent that knows how to decode the packet, and calls its virtual TraceEvent.Dispatch method. Note that TraceEvent does NOT have a copy of the data, but rather just a pointer to it. This data is ONLY valid during the callback. Lookup up the event based on its ProviderID (GUID) and EventId (Classic use the TaskId and the Opcode field for lookup, but use these same fields (see ETWTraceEventSource.RawDispatchClassic) Dispose pattern. Dispose pattern Inserts 'template' into the hash table, using 'providerGuid' and and 'eventID' as the key. For Vista ETW events 'providerGuid' must match the provider GUID and the 'eventID' the ID filed. For PreVist ETW events 'providerGuid must match the task GUID the 'eventID' is the Opcode A helper for creating a set of related guids (knowing the providerGuid can can deduce the 'taskNumber' member of this group. All we do is add the taskNumber to GUID as a number. TraceEventParsers can use this template to define the event for the trivial case where the event has no user-defined payload This is only useful to TraceEventParsers. Construct a TraceEvent template which has no payload fields with the given metadata and action implementation of TraceEvent Interface. implementation of TraceEvent Interface. implementation of TraceEvent Interface. Dispatches the event to the action associated with the template. override When the event has just a single string value associated with it, you can use this shared event template rather than making an event-specific class. The value of the one string payload property. Construct a TraceEvent template which has one string payload field with the given metadata and action implementation of TraceEvent Interface. implementation of TraceEvent Interface. implementation of TraceEvent Interface. implementation of TraceEvent Interface. override UnhandledTraceEvent is a TraceEvent when is used when no manifest information is available for the event. implementation of TraceEvent Interface. implementation of TraceEvent Interface. implementation of TraceEvent Interface. implementation of TraceEvent Interface. override implementation of TraceEvent Interface. There is some work needed to prepare the generic unhandledTraceEvent that we defer late (since we often don't care about unhandled events) TODO this is probably not worht the complexity... ObservableExtensions defines methods on TraceEventParser that implement the IObservable protocol for implementing callbacks. Returns an IObjservable that observes all events that 'parser' knows about that return a T. If eventName is non-null, the event's name must match 'eventName', but if eventName is null, any event that returns a T is observed. This means that Observe{TraceEvent}(parser) will observe all events that the parser can parse. Note that unlike the methods on TraceEventParser, the TraceEvent object returned is already Cloned() and thus can be referenced for as long as you like. Returns an IObjservable that observes all events that 'parser' knows about that return a T and whose event name matches the 'eventNameFilter' predicate. Note that unlike the methods on TraceEventParser, the TraceEvent object returned is already Cloned() and thus can be referenced for as long as you like. Observe a particular event from a particular provider. If eventName is null, it will return every event from the provider Note that unlike the methods on TraceEventParser, the TraceEvent object returned is already Cloned() and thus can be referenced for as long as you like. Given a predicate 'eventToObserve' which takes the name of a provider (which may be of the form Provider(GUID)) (first) and an event name (which may be of the form EventID(NUM)) and indicates which events to observe, return an IObservable that observes those events. Note that unlike the methods on TraceEventParser, the TraceEvent object returned is already Cloned() and thus can be referenced for as long as you like. . Returns an observable that observes all events from the event source 'source' Note that unlike the methods on TraceEventParser, the TraceEvent object returned is already Cloned() and thus can be referenced for as long as you like. Returns an observable that observes all events from the event source 'source' which are not handled by a callback connected to 'source' Note that unlike the methods on TraceEventParser, the TraceEvent object returned is already Cloned() and thus can be referenced for as long as you like. A TraceEventObservable is a helper class that implements the IObservable pattern for TraceEventDispatcher (like ETWTraceEventDispatcher). It is called from the TraceEventParser.Observe*{T} methods. A TraceEventSubscription is helper class that hooks 'callback' and 'completedCallback' to the 'observable' and unhooks them when 'Dispose' is called. TraceEventNativeMethods contains the PINVOKE declarations needed to get at the Win32 TraceEvent infrastructure. It is effectively a port of evntrace.h to C# declarations. Time zone info. Used as one field of TRACE_EVENT_LOGFILE, below. Total struct size is 0xac. EventTraceHeader structure used by EVENT_TRACE_PROPERTIES EVENT_TRACE_PROPERTIES is a structure used by StartTrace, ControlTrace however it can not be used directly in the definition of these functions because extra information has to be hung off the end of the structure before being passed. (LofFileNameOffset, LoggerNameOffset) EventTraceHeader and structure used to defined EVENT_TRACE (the main packet) I have simplified from the original struct definitions. I have omitted alternate union-fields which we don't use. EVENT_TRACE is the structure that represents a single 'packet' of data repesenting a single event. TRACE_LOGFILE_HEADER is a header used to define EVENT_TRACE_LOGFILEW. Total struct size is 0x110. EVENT_TRACE_LOGFILEW Main struct passed to OpenTrace() to be filled in. It represents the collection of ETW events as a whole. EventTraceHeader and structure used to define EVENT_TRACE_LOGFILE (the main packet on Vista and above) I have simplified from the original struct definitions. I have omitted alternate union-fields which we don't use. Provides context information about the event Defines the layout of an event that ETW delivers Possible control commands (borrowed from EventSource) Standard 'update' command to send additional information to a provider Instructs an EventSource-based provider to send its manifest A TraceEventSession represents a single ETW Tracing Session. A session is and event sink that can enable or disable event logging from event providers). TraceEventSessions can log their events either to a file, or by issuing callbacks when events arrive (a so-called 'real time' session). Session are MACHINE wide and unlike most OS resources the operating system does NOT reclaim them when the process that created it dies. By default TraceEventSession tries is best to do this reclamation, but it is possible that for 'orphan' session to accidentally survive if the process is ended abruptly (e.g. by the debugger or a user explicitly killing it). It is possible to turn off TraceEventSession automatic reclamation by setting the StopOnDispose property to false (its default is true). Kernel events have additional restrictions. In particular there is a special API (EnableKernelProvider). Before Windows 8, there was a restriction that kernel events could only be enabled from a session with a special name (see KernelTraceEventParser.KernelSessionName) and thus there could only be a single session that could log kernel events (and that session could not log non-kernel events). These restrictions were dropped in windows 8. Create a new logging session sending the output to a given file. The name of the session. Since session can exist beyond the lifetime of the process this name is used to refer to the session from other processes after it is created. By default TraceEventSessions do their best to close down if the TraceEventSession dies (see StopOnDispose), however if StopOnDispose is set to false, the session can live on after process death, and you use the name to refer to it later. The output moduleFile (by convention .ETL) to put the event data. If this is null, and CircularMB is set to something non-zero, then it will do an in-memory circular buffer. You can get this buffer by using the 'SetFileName()' method which dumps the data in the buffer. Additional flags that influence behavior. Note that the 'Create' option is implied for file mode sessions. Open a logging session. By default (if options is not specified) a new 'real time' session is created if the session already existed it is closed and reopened (thus orphans are cleaned up on next use). By default sessions are closed on Dispose, but if the destructor does not run it can produce 'orphan' session that will live beyond the lifetime of the process. You can use the StopOnDispose property to force sessions to live beyond the TraceEventSession that created them and use the TraceEventSessionOptions.Attach option to reattach to these sessions. The name of the session to open. Should be unique across the machine. Construction options. TraceEventSessionOptions.Attach indicates a desire to attach to an existing session. Looks for an existing active session named 'sessionName; and returns the TraceEventSession associated with it if it exists. Returns null if the session does not exist. You can use the GetActiveSessionNames() to get a list of names to pass to this method. Enable a NON-KERNEL provider (see also EnableKernelProvider) which has a given provider name. This API first checks if a published provider exists by that name, otherwise it assumes it is an EventSouce and determines the provider Guid by hashing the name according to a well known algorithm. Thus it will never return a failure for a incorrect spelling of the name. The name of the provider. It must either be registered with the operating system (logman query providers returns it) or it must be an EventSource (see GetEventSourceGuidFromName) The verbosity to turn on A bitvector representing the areas to turn on. Only the low 32 bits are used by classic providers and passed as the 'flags' value. Zero is a special value which is a provider defined default, which is usually 'everything' Additional options for the provider (e.g. taking a stack trace), arguments ... true if the session already existed and needed to be restarted. Enable a NON-KERNEL provider (see also EnableKernelProvider) which has a given provider Guid. The Guid that represents the event provider enable. The verbosity to turn on A bitvector representing the areas to turn on. Only the low 32 bits are used by classic providers and passed as the 'flags' value. Zero is a special value which is a provider defined default, which is usually 'everything' Additional options for the provider (e.g. taking a stack trace), arguments ... true if the session already existed and needed to be restarted. Enable a NON-KERNEL provider (see also EnableKernelProvider) which has a given provider name. This API first checks if a published provider exists by that name, otherwise it assumes it is an EventSouce and determines the provider Guid by hashing the name according to a well known algorithm. Thus it will never return a failure for a incorrect spelling of the name. The name of the provider. It must either be registered with the operating system (logman query providers returns it) or it must be an EventSource (see GetEventSourceGuidFromName) The verbosity to turn on A bitvector representing the areas to turn on. Only the low 32 bits are used by classic providers and passed as the 'flags' value. Zero is a special value which is a provider defined default, which is usually 'everything' Additional options for the provider (e.g. taking a stack trace) This is set of key-value strings that are passed to the provider for provider-specific interpretation. Can be null if no additional args are needed. If the special key-value pair 'Command'='SendManifest' is provided, then the 'SendManifest' command will be sent (which causes EventSources to re-dump their manifest to the ETW log. true if the session already existed and needed to be restarted. Enable a NON-KERNEL provider (see also EnableKernelProvider) represented by 'providerGuid'. The Guid that represents the event provider enable. The verbosity to turn on A bitvector representing the areas to turn on. Only the low 32 bits are used by classic providers and passed as the 'flags' value. Zero is a special value which is a provider defined default, which is usually 'everything' Additional options for the provider (e.g. taking a stack trace) This is set of key-value strings that are passed to the provider for provider-specific interpretation. Can be null if no additional args are needed. If the special key-value pair 'Command'='SendManifest' is provided, then the 'SendManifest' command will be sent (which causes EventSources to re-dump their manifest to the ETW log. true if the session already existed and needed to be restarted. Enable an ETW provider, passing a raw blob of data to the provider as a Filter specification. Note that this routine is only provided to interact with old ETW providers that can interpret EVENT_FILTER_DESCRIPTOR data but did not conform to the key-value string conventions. This allows this extra information to be passed to these old providers. Ideally new providers follow the key-value convention and EnableProvider can be used. Helper function that is useful when using EnableProvider with key value pairs. Given a list of key-value pairs, create a dictionary of the keys mapping to the values. Enable the kernel provider for the session. Before windows 8 this session must be called 'NT Kernel Session'. This API is OK to call from one thread while Process() is being run on another Specifies the particular kernel events of interest Specifies which events should have their stack traces captured when an event is logged Returns true if the session existed before and was restarted (see TraceEventSession) Turn on windows heap logging (stack for allocation) for a particular existing process. Turn on windows heap logging for a particular EXE file name (just the file name, no directory, but it DOES include the .exe extension) This API is OK to call from one thread while Process() is being run on another Disables a provider with the given provider ID completely Disables a provider with the given name completely Once started, event sessions will persist even after the process that created them dies. They will also be implicitly stopped when the TraceEventSession is closed unless the StopOnDispose property is set to false. This API is OK to call from one thread while Process() is being run on another Close the session and clean up any resources associated with the session. It is OK to call this more than once. This API is OK to call from one thread while Process() is being run on another. Calling Dispose is on a real time session is the way you can force a real time session to stop in a timely manner. Asks all providers to flush events to the session This API is OK to call from one thread while Process() is being run on another For either session create with a file name this method can be used to redirect the data to a new file (so the previous one can be uploaded or processed offline), It can also be used for a in-memory circular buffer session (FileName == null and CircularMB != 0) but its semantics is that simply writes the snapshot to the file (and closes it). It does not actually make the FileName property become non-null because it only flushes the data, it does not cause persistent redirection of the data stream. (it is like it auto-reverts). It is an error to call this on a real time session. (FileName == null and CircularMB == 0) The path to the file to write the data to. If set, whenever a SetFileName is called (causing a new ETL file to be created), force a capture state for every provider that is currently turned on. This way the file will be self-contained (will contain all the capture state information needed to decode events) This setting is true by default. Sends the CAPTURE_STATE command to the provider. This instructs the provider to log any events that are needed to reconstruct important state that was set up before the session started. What is actually done is provider specific. EventSources will re-dump their manifest on this command. This API is OK to call from one thread while Process() is being run on another This routine only works Win7 and above, since previous versions don't have this concept. The providers also has to support it. The GUID that identifies the provider to send the CaptureState command to The Keywords to send as part of the command (can influence what is sent back) if non-zero, this is passed along to the provider as type of the filter data. If non-null this is either an int, or a byte array and is passed along as filter data. When you issue a EnableProvider command, on windows 7 and above it can be done synchronously (that is you know that because the EnableProvider returned that the provider actually got the command). However synchronous behavior means that you may wait forever. This is the time EnableProvider waits until it gives up. Setting this to 0 means asynchronous (fire and forget). The default is 10000 (wait 10 seconds) Before windows 7 EnableProvider is always asynchronous. If set then Stop() will be called automatically when this object is Disposed or Finalized by the GC. This is true BY DEFAULT, so if you want your session to survive past the end of the process you must set this to false. Cause the log to be a circular buffer. The buffer size (in MegaBytes) is the value of this property. Setting this to 0 will cause it to revert to non-circular mode. The setter can only be called BEFORE any provider is enabled. Cause the as a set of files with a given maximum size. The file name must end in .ETL and the output is then a series of files of the form *NNN.ETL (That is it adds a number just before the .etl suffix). If you make your file name *.user.etl then the output will be *.user1.etl, *.user2.etl ... And the MergeInPlace command below will merge them all nicely. You can have more control over this by using a normal sequential file but use the SetFileName() method to redirect the data to new files as needed. Sets the size of the buffer the operating system should reserve to avoid lost packets. Starts out as a very generous 64MB for files. If events are lost, this can be increased, but keep in mind that no value will help if the average incoming rate is faster than the processing rate. The setter can only be called BEFORE any provider is enabled. This is the unit in which data is flushed in Kilobytes. By default it is 64 (KB). By default a TraceEventSession will flush every second, and this amount of space will be transferred to the file. Ideally it is smaller than the number data bytes you expect in a second from any particular processor. It can't be less than 1K per processor on the machine. However if you make it less than 64 (K) you will limit the size of the event that the process can send (they will simply be discarded). The rate at which CPU samples are collected. By default this is 1 (once a millisecond per CPU). There is a lower bound on this (typically .125 Msec) Indicate that this session should use compress the stacks to save space. Must be set before any providers are enabled. Currently only works for kernel events. The name of the session that can be used by other threads to attach to the session. The name of the moduleFile that events are logged to. Null means the session is real time or is a circular in-memory buffer. See also SetFileName() method. If this is a real time session you can fetch the source associated with the session to start receiving events. Currently does not work on file based sources (we expect you to wait until the file is complete). Creating a TraceEventSession does not actually interact with the operating system until a provider is enabled. At that point the session is considered active (OS state that survives a process exit has been modified). IsActive returns true if the session is active. Returns the number of events that should have been delivered to this session but were lost (typically because the incoming rate was too high). This value is up-to-date for real time sessions. Returns true if the session is logging to a circular buffer. This may be in-memory (FileName == null) or to a file (FileName != null) Returns true if the session is Real Time. This means it is not to a file, and not circular. Returns true if this is a in-memory circular buffer (it is circular without an output file). Use SetFileName() to dump the in-memory buffer to a file. ETW trace sessions survive process shutdown. Thus you can attach to existing active sessions. GetActiveSessionNames() returns a list of currently existing session names. These can be passed to the TraceEventSession constructor to open it. A enumeration of strings, each of which is a name of a session Maximum Number of MaxEtwLoggers the system supports Get the maximum number of ETW loggers supported by the current machine The maximum number of supported ETW loggers It is sometimes useful to merge the contents of several ETL files into a single output ETL file. This routine does that. It also will attach additional information that will allow correct file name and symbolic lookup if the ETL file is used on a machine other than the one that the data was collected on. If you wish to transport the file to another machine you need to merge them, even if you have only one file so that this extra information get incorporated. The input ETL files to merge The output ETL file to produce. Optional Additional options for the Merge (seeTraceEventMergeOptions) This variation of the Merge command takes the 'primary' etl file name (X.etl) and will merge in any files that match .clr*.etl .user*.etl. and .kernel.etl. Is the current process Elevated (allowed to turn on a ETW provider). This is useful because you need to be elevated to enable providers on a TraceEventSession. Set the Windows Debug Privilege. Useful because some event providers require this privilege, and and it must be enabled explicitly (even if the process is elevated). The 'properties' field is only the header information. There is 'tail' that is required. 'ToUnmangedBuffer' fills in this tail properly. Returns a sorted dictionary of names and Guids for every provider registered on the system. sets up the EVENT_FILTER_DESCRIPTOR descr to represent the Event Ids in 'eventIds'. You are given the buffer necessary for this (precomputed) for the EVENT_FILTER_EVENT_ID structure. 'enable' is true if this is to enable (otherwise disable) the events, and descrType indicates the descriptor type (either EVENT_FILTER_TYPE_EVENT_ID or EVENT_FILTER_TYPE_STACKWALK) Computes the number of bytes needed for the EVENT_FILTER_EVENT_ID structure to represent 'eventIds' return 0 if there is not need for the filter at all. Cleans out all provider data associated with this session. SetDataForSession sets the filter data for an ETW session by storing it in the registry. This is basically a work-around for the fact that filter data does not get transmitted to the provider if the provider is not alive at the time the controller issues the EnableProvider call. We store in the registry and EventSource looks there for it if it is not present. Note that we support up to 'maxSession' etw sessions simultaneously active (having different filter data). The function return a sessionIndex that indicates which of the 'slots' was used to store the data. This routine also 'garbage collects' data for sessions that have died without cleaning up their filter data. If 'data' is null, then it indicates that no data should be stored and the registry entry is removed. If 'allSesions' is true it means that you want 'old style' data filtering that affects all ETW sessions This is present only used for compatibilty the session index that will be used for this session. Returns -1 if an entry could not be found Given a mask of kernel flags, set the array stackTracingIds of size stackTracingIdsMax to match. It returns the number of entries in stackTracingIds that were filled in. Get a EVENT_TRACE_PROPERTIES structure suitable for passing the the ETW out of a 'buffer' which must be PropertiesSize bytes in size. Used in the TraceEventSession.Merge method No special options Compress the resulting file. Only perform image ID injection. TraceEventProviderOptions represents all the optional arguments that can be passed to EnableProvider command. Create new options object with no options set Create new options object with a set of given provider arguments key-value pairs. There must be a even number of strings provided and each pair forms a key-value pair that is passed to the AddArgument() operator. Arguments are a set of key-value strings that are passed uninterpreted to the EventSource. These can be accessed from the EventSource's command callback. As a convenience, the 'Arguments' property can be modified by calling AddArgument that adds another Key-Value pair to it. If 'Arguments' is not a IDictionary, it is replaced with an IDictionary with the same key-value pairs before the new pair is added. For EventSources, you pass arguments to the EventSource by using key value pairs (this 'Arguments' property). However other ETW providers may expect arguments using another convention. RawArguments give a way of passing raw bytes to the provider as arguments. This is only meant for compatibility with old providers. Setting this property will cause the 'Arguments' property to be ignored. Setting StackEnabled to true will cause all events in the provider to collect stacks when events are fired. Setting ProcessIDFilter will limit the providers that receive the EnableCommand to those that match one of the given Process IDs. Setting ProcessNameFilter will limit the providers that receive the EnableCommand to those that match one of the given Process names (a process name is the name of the EXE without the PATH but WITH the extension). Setting EventIDs to Enable will enable a particular event of a provider by EventID (in addition to those enabled by keywords). Setting EventIDs to Enable will enable the collection of stacks for an event of a provider by EventID (Has no effect if StacksEnabled is also set since that enable stacks for all events IDs) Setting EventIDsToDisable to Enable will disable the event of a provider by EventID This happens after keywords have been processed, so disabling overrides enabling. Setting EventIDs to Enable will disable the collection of stacks for an event of a provider by EventID Has no effect unless StacksEnabled is also set (since otherwise stack collection is off). Setting this to true will cause this provider to be enabled inside of any silos (containers) running on the machine. Setting this to true will cause all events emitted inside of a container to contain the container ID in its payload. Has no effect if EnableInContainers == false. Make a deep copy of options and return it. This return true on OS version beyond 8.1 (windows Version 6.3). It means most of the per-event filtering is supported. This is the backing field for the lazily-computed property. TraceEventSessionOptions indicates special handling when creating a TraceEventSession. Create a new session, stop and recreated it if it already exists. This is the default. Attach to an existing session, fail if the session does NOT already exist. Normally if you create a session it will stop and restart it if it exists already. Setting this flat will disable the 'stop and restart' behavior. This is useful if only a single monitoring process is intended. Write events that were logged on different processors to a common buffer. This is useful when it is important to capture the events in the order in which they were logged. This is not recommended for sessions that expect more than 1K events per second. TraceEventProviders returns information about providers on the system. Given the friendly name of a provider (e.g. Microsoft-Windows-DotNETRuntimeStress) return the GUID for the provider. It does this by looking at all the PUBLISHED providers on the system (that is those registered with wevtutuil). EventSources in particular do not register themselves in this way (see GetEventSourceGuidFromName). Names are case insensitive. It also checks to see if the name is an actual GUID and if so returns that. Returns Guid.Empty on failure. EventSources have a convention for converting its name to a GUID. Use this convention to convert 'name' to a GUID. In this way you can get the provider GUID for a EventSource however it can't check for misspellings. Names are case insensitive. Finds the friendly name for 'providerGuid' Returns the Guid as a string if can't be found. Returns true if 'providerGuid' can be an eventSource. If it says true, there is a 1/16 chance it is not. However if it returns false, it is definitely not following EventSource Guid generation conventions. Returns the Guid of every event provider that published its manifest on the machine. This is the same list that the 'logman query providers' command will generate. It is pretty long (> 1000 entries) A event provider publishes a manifest by compiling its manifest into a special binary form and calling the wevtutil utility. Typically EventSource do NOT publish their manifest but most operating system provider do publish their manifest. Returns the GUID of all event provider that either has registered itself in a running process (that is it CAN be enabled) or that a session has enabled (even if no instances of the provider exist in any process). This is a relatively small list (less than 1000), unlike GetPublishedProviders. Returns a list of provider GUIDs that are registered in a process with 'processID'. Useful for discovering what providers are available for enabling for a particular process. Returns a description of the keywords a particular provider provides. Only works if the provider has published its manifest to the operating system. Throws an exception if providerGuid is not found Returns a list of TRACE_ENABLE_INFO structures that tell about each session (what keywords and level they are set to, for the provider associated with 'providerGuid'. If 'processId != 0, then only providers in that process are returned. A list of these is returned by GetProviderKeywords The name of the provider keyword. The description for the keyword for the provider the value (bitvector) for the keyword. and XML representation for the ProviderDataItem (for debugging) TraceEventProfileSources is the interface for the Windows processor CPU counter support (e.g. causing a stack to be taken every N dcache misses, or branch mispredicts etc) Note that the interface to these is machine global (That is when you set these you cause any session with the kernel PMCProfile keyword active to start emitting PMCCounterProf events for each ProfileSouce that is enabled. /// Returns a dictionary of keyed by name of ProfileSourceInfo structures for all the CPU counters available on the machine. Sets a single Profile Source (CPU machine counters) that will be used if PMC (Precise Machine Counters) are turned on. The profileSourceID is the ID field from the ProfileSourceInfo returned from 'GetInfo()'. and the profileSourceInterval is the interval between sampples (the number of events before a stack is recoreded. If you need more that one (the OS allows up to 4 I think), use the variation of this routine that takes two int[]. Calling this will clear all Profiler sources previously set (it is NOT additive). Sets the Profile Sources (CPU machine counters) that will be used if PMC (Precise Machine Counters) are turned on. Each CPU counter is given a id (the profileSourceID) and has an interval (the number of counts you skip for each event you log). You can get the human name for all the supported CPU counters by calling GetProfileSourceInfo. Then choose the ones you want and configure them here (the first array indicating the CPU counters to enable, and the second array indicating the interval. The second array can be shorter then the first, in which case the existing interval is used (it persists and has a default on boot). Returned by GetProfileSourceInfo, describing the CPU counter (ProfileSource) available on the machine. Human readable name of the CPU performance counter (eg BranchInstructions, TotalIssues ...) The ID that can be passed to SetProfileSources This many events are skipped for each sample that is actually recorded The smallest Interval can be (typically 4K) The largest Interval can be (typically maxInt). These are options to EnableProvider No options Take a stack trace with the event The data model for an Event trace log (ETL) file is simply a stream of events. More sophisticated analysis typically needs a a richer data model then ETL files can provide, and this is the motivation for the ETLX (Event Trace Log eXtended) file format. In particular any analysis that needs non-sequential access to the events or manipulates stack traces associated with events needs the additional support that the ETLX format provides. See the TraceEventProgrammers guide for more on the capabilities of ETLX. The TraceLog class is the programmatic representation of an ETLX file. It represents the ETLX file as a whole. ETLX files are typically created from ETL files using the TraceLog.OpenOrCreate method or more explicitly by the TraceLog.CreateFromEventTraceLogFile. Given the path to an ETW trace log file (ETL) file, create an ETLX file for the data. If etlxFilePath is null the output name is derived from etlFilePath by changing its file extension to .ETLX. The name of the ETLX file that was generated. Given a that can be created from data source, create an ETLX file for the data. If etlxFilePath is null the output name is derived from etlFilePath by changing its file extension to .ETLX. The name of the ETLX file that was generated. Open an ETLX or ETL file as a ETLX file. This routine assumes that you follow normal conventions of naming ETL files with the .ETL file extension and ETLX files with the .ETLX file extension. It further assumes the ETLX file for a given ETL file should be in a file named the same as the ETL file with the file extension changed. etlOrEtlxFilePath can be either the name of the ETL or ETLX file. If the ETLX file does not exist or if it older than the corresponding ETL file then the ETLX file is regenerated with the given options. However if an up-to-date ETLX file exists the conversion step is skipped. Ultimately the ETLX file is opened and the resulting TraceLog instance is returned. From a TraceEventSession, create a real time TraceLog Event Source. Like a ETWTraceEventSource a TraceLogEventSource will deliver events in real time. However an TraceLogEventSource has an underlying Tracelog (which you can access with 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). Note that in order for native stacks to resolve symbolically, you need to have some Kernel events turned on (Image, and Process) and only windows 8 has a session that allows both kernel and user mode events simultaneously. Thus this is most useful on Win 8 systems. Creates a ETLX file an Lttng Text file 'filePath'. Creates a ETLX file an EventPipe 'filePath'. Opens an existing Extended Trace Event log file (ETLX) file. See also TraceLog.OpenOrCreate. All the events in the ETLX file. The returned TraceEvents instance supports IEnumerable so it can be used in foreach statements, but it also supports other methods to further filter the evens before enumerating over them. Note that the TraceEvent returned from this IEnumerable may only be used for one iteration of the foreach. (it is reused for the next event). If you need more lifetime than that you must call Clone() (see 'Lifetime Constraints' in the programmers guide for more). All the Processes that logged an event in the ETLX file. The returned TraceProcesses instance supports IEnumerable so it can be used in foreach statements, but it also supports other methods to select particular a particular process. All the Threads that logged an event in the ETLX file. The returned TraceThreads instance supports IEnumerable so it can be used in foreach statements, but it also supports other methods to select particular thread. All the module files (DLLs) that were loaded by some process in the ETLX file. The returned TraceModuleFiles instance supports IEnumerable so it can be used in foreach statements, but it also supports other methods to select particular module file. All the call stacks in the ETLX file. Normally you don't enumerate over these, but use you use other methods on TraceCallStacks information about code addresses using CallStackIndexes. All the code addresses in the ETLX file. Normally you don't enumerate over these, but use you use other methods on TraceCodeAddresses information about code addresses using CodeAddressIndexes. Summary statistics on the events in the ETX file. If the event has a call stack associated with it, retrieve it. Returns null if there is not call stack associated with the event. If you are retrieving many call stacks consider using GetCallStackIndexForEvent, as it is more efficient. If the event has a call stack associated with it, retrieve CallStackIndex. Returns CallStackIndex.Invalid if there is not call stack associated with the event. Events are given an Index (ID) that are unique across the whole TraceLog. They are not guaranteed to be sequential, but they are guaranteed to be between 0 and MaxEventIndex. Ids can be used to allow clients to associate additional information with event (with a side lookup table). See TraceEvent.EventIndex and EventIndex for more Given an eventIndex, get the event. This is relatively expensive because we need to create a copy of the event that will not be reused by the TraceLog. Ideally you would not use this API but rather use iterate over event using TraceEvents The total number of events in the log. The size of the log file in bytes. override The file path for the ETLX file associated with this TraceLog instance. The machine on which the log was collected. Returns empty string if unknown. The name of the Operating system. Returns empty string if unknown. The build number information for the OS. Returns empty string if unknown. The time the machine was booted. Returns DateTime.MinValue if it is unknown. This is the number of minutes between the local time where the data was collected and UTC time. It is negative if your time zone is WEST of Greenwich. This DOES take Daylights savings time into account but might be a daylight savings time transition happens inside the trace. May be unknown, in which case it returns null. When an ETL file is 'merged', for every DLL in the trace information is added that allows the symbol information (PDBS) to be identified unambiguously on a symbol server. This property returns true if the ETLX file was created from an ETL file with this added information. The size of the main memory (RAM) on the collection machine. Will return 0 if memory size is unknown Are there any event in trace that has a call stack associated with it. If Kernel CPU sampling events are turned on, CPU samples are taken at regular intervals (by default every MSec). This property returns the time interval between samples. If the sampling interval was changed over the course of the trace, this property does not reflect that. It returns the first value it had in the trace. Returns true if the machine running this code is the same as the machine where the trace data was collected. If this returns false, the path names references in the trace cannot be inspected (since they are on a different machine). There is a size limit for ETLX files. Thus it is possible that the data from the original ETL file was truncated. This property returns true if this happened. Returns the EvnetIndex (order in the file) of the first event that has a timestamp smaller than its predecessor. Returns Invalid if there are no time inversions. Returns all the TraceEventParsers associated with this log. An XML fragment that gives useful summary information about the trace as a whole. Create a new real time session called 'sessionName' and connect a TraceLog to it and return that TraceLog. Functionality of TraceLog that does not depend on either remembering past EVENTS or require future knowledge (e.g. stacks of kernel events), will 'just work'. Removes all but the last 'keepCount' entries in 'growableArray' by sliding them down. Forwards an event that was saved (cloned) to the dispatcher associated with the real time source. Flushes any event that has waited around long enough Given a process's virtual address 'address' and an event which acts as a context (determines which process and what time in that process), return a CodeAddressIndex (which represents a particular location in a particular method in a particular DLL). It is possible that different addresses will go to the same code address for the same address (in different contexts). This is because DLLS where loaded in different places in different processes. If an event has a field of type 'Address' the address can be converted to a symbolic value (a TraceCodeAddress) by calling this function. C Given an EventIndex for an event, retrieve the call stack associated with it (that can be given to TraceCallStacks). Many events may not have associated call stack in which case CallSTackIndex.Invalid is returned. Given a eventIndex for a CSWTICH event, return the call stack index for the thread that LOST the processor (the normal callStack is for the thread that GOT the CPU) Given a source of events 'source' generated a ETLX file representing these events from them. This file can then be opened with the TraceLog constructor. 'options' can be null. SetupCallbacks installs all the needed callbacks for TraceLog Processing (stacks, process, thread, summaries etc) on the TraceEventSource rawEvents. Copies the events from the 'rawEvents' dispatcher to the output stream 'IStreamWriter'. It also creates auxiliary data structures associated with the raw events (eg, processes, threads, modules, address lookup maps... Basically any information that needs to be determined by scanning over the events during TraceLog creation should hook in here. This is a helper routine that adds the address 'address' in the event 'data' to the map from events to this list of addresses. Special logic to form MemInfoWSTraceData. We take the single event (which has The working sets for every process in the system, an split them out into N events each of which has the processID for the event set properly, and only has the information for that process. The first 3 processes in the list are -1, -2, and -3 that have special meaning. Given just the stack event and the timestamp for the event the stack event is to attach to, find the IncompleteStack for the event. If the event to attach to cannot be this will return null but otherwise it will make an IncompleteStack entry if one does not already exist or it. As part of allocating an Incomplete stack, it will increment the stack counts for target event. Do the processing necessary to attach the user mode stack 'userModeStack' to any of the stacks in listOfIncompleteKernelStacks. It then clears this list. While doing this processing it will check to see if the target stack 'target' is in that list and it will return true if it was. Do the processing necessary to attach the user mode stack 'userModeStack' to any of the stacks in listOfIncompleteKernelStacks. It then clears this list. While doing this processing it will check to see if the target stack 'target' is in that list and it will return true if it was. Called when we get a definition event (for either a user mode or kernel mode stack fragment). Holds information about stacks associated with an event. This is a transient structure. We only need it until all the information is collected for a particular event, at which point we can create a CallStackIndex for the stack and eventsToStacks table. Clear clears entires that typically don't get set when we only have 1 frame fragment We can recycle the entries without setting these in that case. Clear all entries that can potentially change every time. Log the Kernel Stack fragment. We simply remember all the frames (converted to CodeAddressIndexes). Log the kernel stack fragment. Returns true if all the pieces of the stack fragment are collected (we don't have to log something on the thread). Determine if 'stackInfo' is complete and if so emit it to the 'eventsToStacks' array. If 'force' is true then force what information there is out even if it is not complete (there is nothing else coming). Returns true if it was able to emit the stack returns true if the IncompleteStack is dead (just waiting to be reused). We track the stacks for when CSwitches block, this is the CSWITCH event where that blocking happened. Put the thread that owns 'data' in to the category 'category. Process any extended data (like Win7 style stack traces) associated with 'data' returns true if the event should be considered a bookkeeping event. Dispose pattern Advance 'reader' until it point at a event that occurs on or after 'timeQPC'. on page 'pageIndex'. If 'positions' is non-null, fill in that array. Also return the index in 'positions' for the entry that was found. We need a TraceEventDispatcher in the Enumerators for TraceLog that know how to LOOKUP an event We don't actually dispatch through it. We do mutate the templates (to point a particular data record), but once we are done with it we can reuse this TraceEventDispatcher again an again (it is only concurrent access that is a problem). Thus we have an Allocate and Free pattern to reuse them in the common case of sequential access. The context switch event gives the stack of the thread GETTING the CPU, but it is also very useful to have this stack at the point of blocking. cswitchBlockingEventsToStacks gives this stack. We need to remember the the EventIndexes of the events that were 'just before' this event so we can associate eventToStack traces with the event that actually caused them. PastEventInfo does this. Returns the previous Event on the 'threadID'. Events with -1 thread IDs are also always returned. Returns PastEventInfoIndex.Invalid if there are not more events to consider. Find the event event on thread threadID to the given QPC timestamp. If there is more than one event with the same QPC, we use thread and processor number to disambiguate. Add a new entry that associates the stack 'stackIndex' with the event with index 'eventIndex' Represents a source for a TraceLog file (or real time stream). It is basically a TraceEventDispatcher (TraceEventSource) but you can also get at the TraceLog for it as well. Returns the TraceLog associated with this TraceLogEventSource. Returns the event Index of the 'current' event (we post increment it so it is always one less) override override override TraceEventStats represents the summary statistics (counts) of all the events in the log. The total number of distinct event types (there will be a TraceEventCounts for each distinct event Type) An XML representation of the TraceEventStats (for Debugging) Given an event 'data' look up the statistics for events that type. TraceEventCount holds number of events (Counts) and the number of events with call stacks associated with them (StackCounts) for a particular event type. It also has properties for looking up the event and provider names, but this information can only be complete if all the TraceEventParsers needed were associated with the TraceLog instance. Returns a provider name for events in this TraceEventCounts. It may return a string with a GUID or even UnknownProvider for classic ETW if the event is unknown to the TraceLog. Returns a name for events in this TraceEventCounts. If the event is unknown to the Tracelog it will return EventID(XXX) (for manifest based events) or Task(XXX)/Opcode(XXX) (for classic events) Returns the payload names associated with this Event type. Returns null if the payload names are unknown. Returns true the provider associated with this TraceEventCouts is a classic (not manifest based) ETW provider. Returns the provider GUID of the events in this TraceEventCounts. Returns Guid.Empty if IsClassic Returns the event ID of the events in this TraceEventCounts. Returns TraceEventID.Illegal if IsClassic Returns the Task GUID of the events in this TraceEventCounts. Returns Guid.Empty if not IsClassic Returns the Opcode of the events in the TraceEventCounts. Returns TraceEventOpcode.Info if not IsClassic Returns the average size of the event specific payload data (not the whole event) for all events in the TraceEventsCounts. Returns the number of events in the TraceEventCounts. Returns the number of events in the TraceEventCounts that have stack traces associated with them. Returns the full name of the event (ProviderName/EventName) An XML representation of the top level statistics of the TraceEventCounts. GetHashCode A TraceEvents represents a list of TraceEvent instances. It is IEnumerable<TraceEvent> but also has additional useful ways of filtering the list. Note that the TraceEvent returned from this IEnumerable may only be used for one iteration of the foreach. (it is reused for the next event). If you need more lifetime than that you must call Clone() (see 'Lifetime Constraints' in the programmers guide for more). Returns a list of events in the TraceEvents that return a payload of type T. Thus ByEventType < TraceEvent > returns all events. Returns a TraceEventDispatcher (a push model object on which you can register callbacks for particular events) that will push all the vents in the TraceEvents. Note that the TraceEvent returned from this callback may only be used for the duration of the callback. If you need more lifetime than that you must call Clone() (see 'Lifetime Constraints' in the programmers guide for more). Returns a new list which is the same as the TraceEvents but the events are delivered from last to first. This allows you to search backwards in the event stream. Filter the events by time. Both starTime and endTime are inclusive. Filter the events by time. StartTimeRelativeMSec and endTimeRelativeMSec are relative to the SessionStartTime and are inclusive. Create new list of Events that has all the events in the current TraceEvents that pass the given predicate. Returns the TraceLog associated with the events in the TraceEvents Returns a time that is guaranteed to be before the first event in the TraceEvents list. It is returned as DateTime Returns a time that is guaranteed to be before the first event in the TraceEvents list. It is returned as floating point number of MSec since the start of the TraceLog Returns a time that is guaranteed to be after the last event in the TraceEvents list. It is returned as DateTime Returns a time that is guaranteed to be after the last event in the TraceEvents list. It is returned as floating point number of MSec since the start of the TraceLog Each process is given a unique index from 0 to TraceProcesses.Count-1 and unlike the OS Process ID, is unambiguous (The OS process ID can be reused after a process dies). ProcessIndex represents this index. By using an enum rather than an int it allows stronger typing and reduces the potential for errors. It is expected that users of this library might keep arrays of size TraceProcesses.Count to store additional data associated with a process in the trace. Returned when no appropriate Process exists. A TraceProcesses instance represents the list of processes in the Event log. TraceProcesses are IEnumerable, and will return the processes in order of creation time. The log associated with this collection of processes. The count of the number of TraceProcess instances in the TraceProcesses list. Each process that occurs in the log is given a unique index (which unlike the PID is unique), that ranges from 0 to Count - 1. Return the TraceProcess for the given index. Given an OS process ID and a time, return the last TraceProcess that has the same process ID, and whose process start time is less than 'timeRelativeMSec'. If 'timeRelativeMSec' is during the processes's lifetime this is guaranteed to be the correct process. for the given process ID since process IDs are unique during the lifetime of the process. If timeRelativeMSec == TraceLog.SessionDuration this method will return the last process with the given process ID, even if it had died during the trace. Returns the last process in the log with the given process ID. Useful when the logging session was stopped just after the processes completed (a common scenario). Find the first process in the trace that has the process name 'processName' and whose process start time is after the given point in time. A process's name is the file name of the EXE without the extension. Processes that began before the trace started have a start time of 0, Thus specifying 0 for the time will include processes that began before the trace started. Find the last process in the trace that has the process name 'processName' and whose process start time is after the given point in time. A process's name is the file name of the EXE without the extension. Processes that began before the trace started have a start time of 0, Thus specifying 0 for the time will include processes that began before the trace started. An XML representation of the TraceEventProcesses (for debugging) Enumerate all the processes that occurred in the trace log, ordered by creation time. Given an OS process ID and a time, return the last TraceProcess that has the same process ID, and whose offset start time is less than 'timeQPC'. If 'timeQPC' is during the thread's lifetime this is guaranteed to be the correct process. Using timeQPC = TraceLog.sessionEndTimeQPC will return the last process with the given PID, even if it had died. TraceProcesses represents the entire ETL moduleFile log. At the node level it is organized by threads. The TraceProcesses also is where we put various caches that are independent of the process involved. These include a cache for TraceModuleFile that represent native images that can be loaded into a process, as well as the process lookup tables and a cache that remembers the last calls to GetNameForAddress(). A TraceProcess represents a process in the trace. The OS process ID associated with the process. It is NOT unique across the whole log. Use ProcessIndex for that. The index into the logical array of TraceProcesses for this process. Unlike ProcessID (which may be reused after the process dies, the process index is unique in the log. This is a short name for the process. It is the image file name without the path or suffix. The command line that started the process (may be empty string if unknown) The path name of the EXE that started the process (may be empty string if unknown) The time when the process started. Returns the time the trace started if the process existed when the trace started. The time when the process started. Returns the time the trace started if the process existed when the trace started. Returned as the number of MSec from the beginning of the trace. The time when the process ended. Returns the time the trace ended if the process existed when the trace ended. Returned as a DateTime The time when the process ended. Returns the time the trace ended if the process existed when the trace ended. Returned as the number of MSec from the beginning of the trace. The process ID of the parent process The process that started this process. Returns null if unknown Unlike ParentID the chain of Parent's will never form a loop. If the process exited, the exit status of the process. Otherwise null. The amount of CPU time spent in this process based on the kernel CPU sampling events. Returns true if the process is a 64 bit process The log file associated with the process. A list of all the threads that occurred in this process. Returns the list of modules that were loaded by the process. The modules may be managed or native, and include native modules that were loaded event before the trace started. Filters events to only those for a particular process. Filters events to only that occurred during the time the process was alive. An XML representation of the TraceEventProcess (for debugging) Sets the 'Parent' field for the process (based on the ParentID). sentinel is internal to the implementation, external callers should always pass null. TraceProcesses that have a parent==sentinel considered 'illegal' since it would form a loop in the parent chain, which we definitely don't want. Create a new TraceProcess. It should only be done by log.CreateTraceProcess because only TraceLog is responsible for generating a new ProcessIndex which we need. 'processIndex' is a index that is unique for the whole log file (where as processID can be reused). This table allows us to intern codeAddress so we only at most one distinct address per process. We also keep track of those code addresses that are NOT yet resolved to at least a File (for JIT compiled things this would be to a method This is all the information needed to remember about at JIT compiled method (used in the jitMethods variable) This table has a entry for each JIT compiled method that remembers its range. It is actually only needed for the real time case, as the non-real time case you resolve code addresses on method unload/rundown and thus don't need to remember the information. This table is NOT persisted in the ETLX file since is only needed to convert raw addresses into TraceMethods. It is a array of arrays to make insertion efficient. Most of the time JIT methods will be added in contiguous memory (thus will be in order), however from time to time things will 'jump around' to a new segment. By having a list of lists, (which are in order in both lists) you can efficiently (log(N)) search as well as insert. Maps a newly scheduled "user" activity ID to the ActivityIndex of the Activity. This keeps track of currently created/scheduled activities that have not started yet, and for multi-trigger events, created/scheduled activities that have not conclusively "died" (e.g. by having their "user" activity ID reused by another activity). Each thread is given a unique index from 0 to TraceThreads.Count-1 and unlike the OS Thread ID, is unambiguous (The OS thread ID can be reused after a thread dies). ThreadIndex represents this index. By using an enum rather than an int it allows stronger typing and reduces the potential for errors. It is expected that users of this library might keep arrays of size TraceThreads.Count to store additional data associated with a process in the trace. Returned when no appropriate Thread exists. A TraceThreads represents the list of threads in a process. Enumerate all the threads that occurred in the trace log. It does so in order of their thread offset events in the log. The count of the number of TraceThreads in the trace log. Each thread that occurs in the log is given a unique index (which unlike the PID is unique), that ranges from 0 to Count - 1. Return the TraceThread for the given index. Given an OS thread ID and a time, return the last TraceThread that has the same thread ID, and whose start time is less than 'timeRelativeMSec'. If 'timeRelativeMSec' is during the thread's lifetime this is guaranteed to be the correct thread. An XML representation of the TraceThreads (for debugging) TraceThreads represents the collection of threads in a process. Get the thread for threadID and timeQPC. Create if necessary. If 'isThreadCreateEvent' is true, then force the creation of a new thread EVEN if the thread exist since we KNOW it is a new thread (and somehow we missed the threadEnd event). Process is the process associated with the thread. It can be null if you really don't know the process ID. We will try to fill it in on another event where we DO know the process id (ThreadEnd event). A TraceThread represents a thread of execution in a process. The OS process ID associated with the process. The index into the logical array of TraceThreads for this process. Unlike ThreadId (which may be reused after the thread dies) the T index is unique over the log. The process associated with the thread. The time when the thread started. Returns the time the trace started if the thread existed when the trace started. Returned as a DateTime The time when the thread started. Returns the time the trace started if the thread existed when the trace started. Returned as the number of MSec from the beginning of the trace. The time when the thread ended. Returns the time the trace ended if the thread existed when the trace ended. Returned as a DateTime The time when the thread ended. Returns the time the trace ended if the thread existed when the trace ended. Returned as the number of MSec from the beginning of the trace. The amount of CPU time spent on this thread based on the kernel CPU sampling events. Filters events to only those for a particular thread. Filters events to only those that occurred during the time a the thread was alive. REturns the activity this thread was working on at the time instant 'relativeMsec' Represents the "default" activity for the thread, the activity that no one has set ThreadInfo is a string that identifies the thread symbolically. (e.g. .NET Threadpool, .NET GC) It may return null if there is no useful symbolic name. VerboseThreadName is a name for the thread including the ThreadInfo and the CPU time used. The base of the thread's stack. This is just past highest address in memory that is part of the stack (we don't really know the lower bound (userStackLimit is this lower bound at the time the thread was created which is not very useful). An XML representation of the TraceThread (for debugging) Create a new TraceProcess. It should only be done by log.CreateTraceProcess because only TraceLog is responsible for generating a new ProcessIndex which we need. 'processIndex' is a index that is unique for the whole log file (where as processID can be reused). This is a list of the activities (snippet of threads) that have run on this thread. They are ordered by time so you can binary search for your activity based on timestamp. We want to have the stack for when CSwtichs BLOCK as well as when they unblock. this variable keeps track of the last blocking CSWITCH on this thread so that we can compute this. It is only used during generation of a TraceLog file. TraceLoadedModules represents the collection of modules (loaded DLLs or EXEs) in a particular process. The process in which this Module is loaded. Returns the module which was mapped into memory at at 'timeRelativeMSec' and includes the address 'address' Note that Jit compiled code is placed into memory that is not associated with the module and thus will not be found by this method. Returns the module representing the unmanaged load of a particular fiele at a given time. An XML representation of the TraceLoadedModules (for debugging) Returns all modules in the process. Note that managed modules may appear twice (once for the managed load and once for an unmanaged (LoadLibrary) load. This function will find the module associated with 'address' at 'timeQPC' however it will only find modules that are mapped in memory (module associated with JIT compiled methods will not be found). Finds the index and module for an a given managed module ID. If not found, new module should be inserted at index + 1; Finds the index and module for an address that lives within the image. If the module did not match the new entry should go at index+1. A TraceLoadedModule represents a module (DLL or EXE) that was loaded into a process. It represents the time that this module was mapped into the processes address space. The address where the DLL or EXE was loaded. Will return 0 for managed modules without NGEN images. The load time is the time the LoadLibrary was done if it was loaded from a file, otherwise is the time the CLR loaded the module. Expressed as a DateTime The load time is the time the LoadLibrary was done if it was loaded from a file, otherwise is the time the CLR loaded the module. Expressed as as MSec from the beginning of the trace. The load time is the time the FreeLibrary was done if it was unmanaged, otherwise is the time the CLR unloaded the module. Expressed as a DateTime The load time is the time the FreeLibrary was done if it was unmanaged, otherwise is the time the CLR unloaded the module. Expressed as MSec from the beginning of the trace. The process that loaded this module An ID that uniquely identifies the module in within the process. Works for both the managed and unmanaged case. If this managedModule was a file that was mapped into memory (eg LoadLibary), then ModuleFile points at it. If a managed module does not have a file associated with it, this can be null. Shortcut for ModuleFile.FilePath, but returns the empty string if ModuleFile is null Shortcut for ModuleFile.Name, but returns the empty string if ModuleFile is null Because .NET applications have AppDomains, a module that is loaded once from a process perspective, might be loaded several times (once for each AppDomain) from a .NET perspective This property returns the loadedModule record for the first such managed module load associated with this load. An XML representation of the TraceLoadedModule (used for debugging) See IFastSerializable.ToStream. See IFastSerializable.FromStream. A TraceManagedModule represents the loading of a .NET module into .NET AppDomain. It represents the time that that module an be used in the AppDomain. The module ID that the .NET Runtime uses to identify the file (module) associated with this managed module The Assembly ID that the .NET Runtime uses to identify the assembly associated with this managed module. Returns true if the managed module was loaded AppDOmain Neutral (its code can be shared by all appdomains in the process. If the managed module is an IL module that has an NGEN image, return it. An XML representation of the TraceManagedModule (used for debugging) CallStackIndex uniquely identifies a callstack within the log. Valid values are between 0 and TraceCallStacks.Count-1. Thus, an array can be used to 'attach' data to a call stack. Returned when no appropriate CallStack exists. Call stacks are so common in most traces, that having a .NET object (a TraceEventCallStack) for each one is often too expensive. As optimization, TraceLog also assigns a call stack index to every call stack and this index uniquely identifies the call stack in a very light weight fashion. To be useful, however you need to be able to ask questions about a call stack index without creating a TraceEventCallStack. This is the primary purpose of a TraceCallStacks (accessible from TraceLog.CallStacks). It has a set of methods that take a CallStackIndex and return properties of the call stack (like its caller or its code address). Returns the count of call stack indexes (all Call Stack indexes are strictly less than this). Given a call stack index, return the code address index representing the top most frame associated with it Given a call stack index, look up the call stack index for caller. Returns CallStackIndex.Invalid at top of stack. Given a call stack index, returns the number of callers for the call stack Given a call stack index, returns a TraceCallStack for it. Returns the TraceCodeAddresses instance that can resolve CodeAddressIndexes in the TraceLog Given a call stack index, returns the ThreadIndex which represents the thread for the call stack Given a call stack index, returns the TraceThread which represents the thread for the call stack An XML representation of the TraceCallStacks (used for debugging) IEnumerable Support Used to 'undo' the effects of adding a eventToStack that you no longer want. This happens when we find out that a eventToStack is actually got more callers in it (when a eventToStack is split). Returns an index that represents the 'threads' of the stack. It encodes the thread which owns this stack into this. We encode this as -ThreadIndex - 2 (since -1 is the Invalid node) A TraceCallStack is a structure that represents a call stack as a linked list. Each TraceCallStack contains two properties, the CodeAddress for the current frame, and the TraceCallStack of the caller of this frame. The Caller property will return null at the thread start frame. Return the CallStackIndex that uniquely identifies this call stack in the TraceLog. Returns the TraceCodeAddress for the current method frame in the linked list of frames. The TraceCallStack for the caller of of the method represented by this call stack. Returns null at the end of the list. The depth (count of callers) of this call stack. An XML representation of the TraceCallStack (used for debugging) Writes an XML representation of the TraceCallStack to the stringbuilder 'sb' CodeAddressIndex uniquely identifies a symbolic codeAddress within the log . Valid values are between 0 and TraceCodeAddresses.Count. Thus, an array can be used to 'attach' data to a code address. Returned when no appropriate Method exists. Code addresses are so common in most traces, that having a .NET object (a TraceCodeAddress) for each one is often too expensive. As optimization, TraceLog also assigns a code address index to every code address and this index uniquely identifies the code address in a very light weight fashion. To be useful, however you need to be able to ask questions about a code address index without creating a TraceCodeAddress. This is the primary purpose of a TraceCodeAddresses (accessible from TraceLog.CodeAddresses). It has a set of methods that take a CodeAddressIndex and return properties of the code address (like its method, address, and module file) Chunk size for Returns the count of code address indexes (all code address indexes are strictly less than this). Given a code address index, return the name associated with it (the method name). It will have the form MODULE!METHODNAME. If the module name is unknown a ? is used, and if the method name is unknown a hexadecimal number is used as the method name. Given a code address index, returns the virtual address of the code in the process. Given a code address index, returns the index for the module file (representing the file's path) Given a code address index, returns the index for the method associated with the code address (it may return MethodIndex.Invalid if no method can be found). Given a code address index, returns the module file (the DLL paths) associated with it If the code address is associated with managed code, return the IL offset within the method. If the method is unmanaged -1 is returned. To determine the IL offset the PDB for the NGEN image (for NGENed code) or the correct .NET events (for JIT compiled code) must be present. If this information is not present -1 is returned. Given a code address index, returns a TraceCodeAddress for it. Returns the TraceMethods object that can look up information from MethodIndexes Returns the TraceModuleFiles that can look up information about ModuleFileIndexes Indicates the number of managed method records that were encountered. This is useful to understand if symbolic information 'mostly works'. Initially CodeAddresses for unmanaged code will have no useful name. Calling LookupSymbolsForModule lets you resolve the symbols for a particular file so that the TraceCodeAddresses for that DLL will have Methods (useful names) associated with them. A TraceCodeAddress can contain a method name, but does not contain number information. To find line number information you must read the PDB again and fetch it. This is what GetSoruceLine does. Given a SymbolReader (which knows how to look up PDBs) and a code address index (which represent a particular point in execution), find a SourceLocation (which represents a particular line number in a particular source file associated with the code address. Returns null if anything goes wrong (and diagnostic information will be written to the log file associated with the SymbolReader. The number of times a particular code address appears in the log. Unlike TraceCodeAddresses.Count, which tries to share a code address as much as possible, TotalCodeAddresses counts the same code address in different call stacks (and even if in the same stack) as distinct. This makes TotalCodeAddresses a better measure of the 'popularity' of a particular address (which can factor into decisions about whether to call LookupSymbolsForModule) The sum of ModuleFile.CodeAddressesInModule for all modules should sum to this number. If set to true, will only use the name of the module and not the PDB GUID to confirm that a PDB is correct for a given DLL. Setting this value is dangerous because it is easy for the PDB to be for a different version of the DLL and thus give inaccurate method names. Nevertheless, if a log file has no PDB GUID information associated with it, unsafe PDB matching is the only way to get at least some symbolic information. Returns an XML representation of the TraceCodeAddresses (for debugging) We expose ILToNativeMap internally so we can do diagnostics. IEnumerable support. Called when JIT CLR Rundown events are processed. It will look if there is any address that falls into the range of the JIT compiled method and if so log the symbolic information (otherwise we simply ignore it) Adds a JScript method Allows you to get a callback for each code address that is in the range from start to start+length within the process 'process'. If 'considerResolved' is true' then the address range is considered resolved and future calls to this routine will not find the addresses (since they are resolved). Gets the symbolic information entry for 'address' which can be any address. If it falls in the range of a symbol, then that symbolic information is returned. Regardless of whether symbolic information is found, however, an entry is created for it, so every unique address has an entry in this table. All processes might have kernel addresses in them, this returns the kernel process (process ID == 0) if 'address' is a kernel address. Sort from lowest address to highest address. Do symbol resolution for all addresses in the log file. Look up the SymbolModule (open PDB) for a given moduleFile. Will generate NGEN pdbs as needed. Returns true if 'moduleFile' seems to be unchanged from the time the information about it was generated. Logs messages to 'log' if it fails. Specify overrideModuleFilePath if the path needs to be converted to a different format in order to be accessed (e.g. from device path to volume path). A CodeAddressInfo is the actual data stored in the ETLX file that represents a TraceCodeAddress. It knows its Address in the process and it knows the TraceModuleFile (which knows its base address), so it also knows its relative address in the TraceModuleFile (which is what is needed to look up the value in the PDB. Note that by the time that the CodeAddressInfo is persisted in the ETLX file it no longer knows the process it originated from (thus separate processes with the same address and same DLL file loaded at the same address can share the same CodeAddressInfo. This is actually reasonably common, since OS tend to load at their preferred base address. We also have to handle the managed case, in which case the CodeAddressInfo may also know about the TraceMethod or the ILMapIndex (which remembers both the method and the line numbers for managed code. However when the CodeAddressInfo is first created, we don't know the TraceModuleFile so we also need to remember the Process This is only valid until MethodIndex or ModuleFileIndex is set. Only for managed code. Only for unmanaged code. TODO, this can be folded into methodOrProcessIlMap index and save a DWORD. since if the method or IlMap is present then you can get the ModuelFile index from there. This is a count of how many times this code address appears in any stack in the trace. It is a measure of what popular the code address is (whether we should look up its symbols). Find the ILToNativeMap for 'methodId' in process associated with 'processIndex' and then remove it from the table (this is what you want to do when the method is unloaded) Conceptually a TraceCodeAddress represents a particular point of execution within a particular line of code in some source code. As a practical matter, they are represented two ways depending on whether the code is managed or not. * For native code (or NGened code), it is represented as a virtual address along with the loaded native module that includes that address along with its load address. A code address does NOT know its process because they can be shared among all processes that load a particular module at a particular location. These code addresses will not have methods associated with them unless symbols information (PDBS) are loaded for the module using the LookupSymbolsForModule. * For JIT compiled managed code, the address in a process is eagerly resolved into a method, module and an IL offset and that is stored in the TraceCodeAddress. Sometimes it is impossible to even determine the module associated with a virtual address in a process. These are represented as simply the virtual address. Because code addresses are so numerous, consider using CodeAddressIndex instead of TraceCodeAddress to represent a code address. Methods on TraceLog.CodeAddresses can access all the information that would be in a TraceCodeAddress from a CodeAddressIndex without the overhead of creating a TraceCodeAddress object. The CodeAddressIndex that uniquely identifies the same code address as this TraceCodeAddress The Virtual address of the code address in the process. (Note that the process is unknown by the code address to allow for sharing) The full name (Namespace name.class name.method name) of the method associated with this code address. Returns the empty string if no method is associated with the code address. Returns the TraceMethod associated with this code address or null if there is none. If the TraceCodeAddress is associated with managed code, return the IL offset within the method. If the method is unmanaged -1 is returned. To determine the IL offset the PDB for the NGEN image (for NGENed code) or the correct .NET events (for JIT compiled code) must be present. If this information is not present -1 is returned. A TraceCodeAddress can contain a method name, but does not contain number information. To find line number information you must read the PDB again and fetch it. This is what GetSoruceLine does. Given a SymbolReader (which knows how to look up PDBs) find a SourceLocation (which represents a particular line number in a particular source file associated with the current TraceCodeAddress. Returns null if anything goes wrong (and diagnostic information will be written to the log file associated with the SymbolReader. Returns the TraceModuleFile representing the DLL path associated with this code address (or null if not known) ModuleName is the name of the file without path or extension. The full path name of the DLL associated with this code address. Returns empty string if not known. The CodeAddresses container that this Code Address lives within An XML representation for the CodeAddress (for debugging) Writes an XML representation for the CodeAddress to the stringbuilder sb MethodIndex uniquely identifies a method within the log. Valid values are between 0 and TraceMethods.Count-1. Thus, an array can be used to 'attach' data to a method. Returned when no appropriate Method exists. Methods are so common in most traces, that having a .NET object (a TraceMethod) for each one is often too expensive. As optimization, TraceLog also assigns a method index to every method and this index uniquely identifies the method in a very light weight fashion. To be useful, however you need to be able to ask questions about a method index without creating a TraceMethod. This is the primary purpose of a TraceMethods (accessible from TraceLog.CodeAddresses.Methods). It has a set of methods that take a MethodIndex and return properties of the method (like its name, and module file) Returns the count of method indexes. All MethodIndexes are strictly less than this. Given a method index, if the method is managed return the IL meta data MethodToken (returns 0 for native code) Given a method index, return the Method's RVA (offset from the base of the DLL in memory) (returns 0 for managed code) Given a method index, return the index for the ModuleFile associated with the Method Index. Given a method index, return the Full method name (Namespace.ClassName.MethodName) associated with the Method Index. Given a method index, return a TraceMethod that also represents the method. Returns an XML representation of the TraceMethods. IEnumerable support A TraceMethod represents the symbolic information for a particular method. To maximizes haring a TraceMethod has very little state, just the module and full method name. Each Method in the TraceLog is given an index that uniquely identifies it. This return this index for this TraceMethod The full name of the method (Namespace.ClassName.MethodName). .Net runtime methods have a token (32 bit number) that uniquely identifies it in the meta data of the managed DLL. This property returns this token. Returns 0 for unmanaged code or method not found. For native code the RVA (relative virtual address, which is the offset from the base of the file in memory) for the method in the file. Returns 0 for managed code or method not found; Returns the index for the DLL ModuleFile (which represents its file path) associated with this method Returns the ModuleFile (which represents its file path) associated with this method A XML representation of the TraceMethod. (Used for debugging) Writes an XML representation of the TraceMethod to the stringbuilder 'sb' Returns a new string prefixed with the optimization tier if it would be useful. Typically used to adorn a method's name with the optimization tier of the specific code version of the method. A ModuleFileIndex represents a particular file path on the disk. It is a number from 0 to MaxModuleFileIndex, which means that you can create a side array to hold information about module files. You can look up information about the ModuleFile from the ModuleFiles type. Returned when no appropriate ModuleFile exists. TraceModuleFiles is the list of all the ModuleFiles in the trace. It is an IEnumerable. Each file is given an index for quick lookup. Count is the maximum such index (thus you can create an array that is 1-1 with the files easily). Given a ModuleFileIndex, find the TraceModuleFile which also represents it Returns the TraceLog associated with this TraceModuleFiles Returns an XML representation of the TraceModuleFiles Enumerate all the files that occurred in the trace log. We cache information about a native image load in a TraceModuleFile. Retrieve or create a new cache entry associated with 'nativePath' and 'moduleImageBase'. 'moduleImageBase' can be 0 for managed assemblies that were not loaded with LoadLibrary. For a given file name, get the TraceModuleFile associated with it. The TraceModuleFile represents a executable file that can be loaded into memory (either an EXE or a DLL). It represents the path on disk as well as the location in memory where it loads (or its ModuleID if it is a managed module), but not the load or unload time or the process in which it was loaded (this allows them to be shared within the trace). The ModuleFileIndex ID that uniquely identifies this module file. The moduleFile name associated with the moduleFile. May be the empty string if the moduleFile has no moduleFile (dynamically generated). For managed code, this is the IL moduleFile name. This is the short name of the moduleFile (moduleFile name without extension). Returns the address in memory where the dll was loaded. Returns the size of the DLL when loaded in memory Returns the address just past the memory the module uses. The name of the symbol file (PDB file) associated with the DLL Returns the GUID that uniquely identifies the symbol file (PDB file) for this DLL Returns the age (which is a small integer), that is also needed to look up the symbol file (PDB file) on a symbol server. Returns the file version string that is optionally embedded in the DLL's resources. Returns the empty string if not present. Returns the product name recorded in the file version information. Returns empty string if not present Returns a version string for the product as a whole (could include GIT source code hash). Returns empty string if not present This is the checksum value in the PE header. Can be used to validate that the file on disk is the same as the file from the trace. This used to be called TimeDateStamp, but linkers may not use it as a timestamp anymore because they want deterministic builds. It still is useful as a unique ID for the image. Tells if the module file is ReadyToRun (the has precompiled code for some managed methods) If the Product Version fields has a GIT Commit Hash component, this returns it, Otherwise it is empty. Returns the time the DLL was built as a DateTime. Note that this may not work if the build system uses deterministic builds (in which case timestamps are not allowed. We may not be able to tell if this is a bad timestamp but we include it because when it is timestamp it is useful. The number of code addresses included in this module. This is useful for determining if this module is worth having its symbolic information looked up or not. It is not otherwise a particularly interesting metric. This number is defined as the number of appearances this module has in any stack or any event with a code address (If the modules appears 5 times in a stack that counts as 5 even though it is just one event's stack). If the module file was a managed native image, this is the IL file associated with it. Returns an XML representation of the TraceModuleFile (for debugging) A ActivityIndex uniquely identifies an Activity in the log. Valid values are between 0 and Activities.Count-1. valid activity indexes are non-negative integers Representation of an Activity. An activity can be thought of as a unit of execution associated with a task or workitem; it executes on one thread, and has a start and end time. An activity keeps track of its "creator" or "caller" -- which is the activity that scheduled it. Using the "creator" link a user can determine the chain of activities that led up to the current one. Given an event you can get the Activity for the event using the Activity() extension method. Describes the kinds of known Activities (used for descriptive purposes alone) Invalid Default activity on a thread (when the thread does not execute any code on behalf of anyone else) An activity that was initiated by a Task.Run An activity that's a task, but for which we didn't see a "Scheduled" event An activity that allows correlation between the antecedent and continuation A thread started with Thread.Start Native CLR threadpool workitem Native CLR IO threadpool workitem Managed threadpool workitem Generic managed thread transfer Managed async IO workitem WinRT Dispatched workitem Used when we make up ones because we know that have to be there but we don't know enough to do more than that. An activity that allows correlation between the antecedent and continuation if have bit 5 set it means you auto-compete Same as TaskWait, hwoever it auto-completes Managed timer workitem A trace-wide unique id identifying an activity The activity that initiated or caused the current one This return an unique string 'name' for the activity. It is a the Index followed by a - followed by the TPL index (if available). It is a bit nicer since it gives more information for debugging. Computes the creator path back to root. The thread on which the activity is running True if there may be multiple activities that were initiated by caller (e.g. managed Timers) A descriptive label for the activity TODO: eliminate and use ToString()? A thread activity is the activity associate with an OS thread. It is special because it may have a region that is disjoint. Time from beginning of trace (in msec) when activity started executing Time from beginning of trace (in msec) when activity completed execution. Does not include children. The event index of the TraceEvent instance that created/scheduled this activity The call stack index of the TraceEvent instance that scheduled (caused the creation of) the activity Time from beginning of trace (in msec) when activity was scheduled To use mainly for debugging TraceLogOptions control the generation of a TraceLog (ETLX file) from an ETL file. Creates a new object containing options for constructing a TraceLog file. If non-null, this is a predicate that, given a file path to a dll, answers the question whether the PDB associated with that DLL be looked up and its symbolic information added to the TraceLog file as part of conversion. Symbols can be looked up afterward when the file is later opened, so the default (which is to look up no symbols during conversion) is typically OK. Resolving symbols from a symbol server can take a long time. If there is a DLL that always fails, it can be quite annoying because it will always cause delays, By specifying only local symbols it will only resolve the symbols if it can do so without the delay of network traffic. Symbols that have been previously cached locally from a symbol server count as local symbols. By default symbols are only resolved if there are stacks associated with the trace. Setting this option forces resolution even if there are no stacks. Writes status to this log. Useful for debugging symbol issues. If ConversionLogName is set, it indicates that any messages associated with creating the TraceLog should be written here. ETL files typically contain a large number of 'bookkeeping' event for resolving names of files, or methods or to indicate information about processes that existed when the trace was started (DCStart and DCStop events). By default these events are stripped from the ETLX file because their information has already been used to do the bookkeeping as part of the conversion However sometimes it is useful to keep these events (typically for debugging TraceEvent itself) and setting this property to true will cause every event in the ETL file to be copied as an event to the ETLX file. Sometimes ETL files are too big , and you just want to look at a fraction of it to speed things up (or to keep file size under control). The MaxEventCount property allows that. 10M will produce a 3-4GB ETLX file. 1M is a good value to keep ETLX file size under control. Note that that the conversion still scan the entire original ETL file too look for bookkeeping events, however MaxEventCount events will be transferred to the ETLX file as events. The default is 10M because ETLX has a restriction of 4GB in size. If an ETL file has too many events for efficient processing the first part of the trace can be skipped by setting this property. Any event which happens before 'SkipMSec' into the session will be filtered out. This property is intended to be used along with the MaxEventCount property to carve out a arbitrary chunk of time from an ETL file as it is converted to an ETLX file. If this delegate is non-null, it is called if there are any lost events or if the file was truncated. It is passed a bool whether the ETLX file was truncated, as well as the number of lost events and the total number of events in the ETLX file. You can throw if you want to abort. If you have the manifests for particular providers, you can read them in explicitly by setting this directory. All files of the form *.manifest.xml will be read into the DynamicTraceEventParser's database before conversion starts. If errors occur during conversion, just assume the traced ended at that point and continue. The TraceEvent instances returned during the processing of a TraceLog have additional capabilities that these extension methods can access. Finds the TraceProcess associated with a TraceEvent. Guaranteed to be non-null for non-real-time sessions if the process ID is != -1 Finds the TraceThread associated with a TraceEvent. Guaranteed to be non-null for non-real-time sessions if the process ID is != -1 Finds the TraceLog associated with a TraceEvent. Finds the TraceCallStack associated with a TraceEvent. Returns null if the event does not have callstack. Finds the CallStack index associated with a TraceEvent. Returns Invalid if the event does not have callstack. Finds the CallStack index associated the blocking thread for CSwitch event Finds the TraceCallStacks associated with a TraceEvent. Finds the Activity associated with a TraceEvent Finds the ActivityIndex associated with a TraceEvent For a PageFaultTraceData event, gets the TraceCodeAddress associated with the ProgramCounter address. For a PageFaultTraceData event, gets the CodeAddressIndex associated with the ProgramCounter address. For a SampledProfileTraceData event, gets the TraceCodeAddress associated with the InstructionPointer address. For a SampledProfileTraceData event, gets the CodeAddressIndex associated with the InstructionPointer address. For a SysCallEnterTraceData event, gets the CodeAddressIndex associated with the SysCallAddress address. For a PMCCounterProfTraceData event, gets the TraceCodeAddress associated with the InstructionPointer address. For a PMCCounterProfTraceData event, gets the CodeAddressIndex associated with the InstructionPointer address. For a ISRTraceData event, gets the CodeAddressIndex associated with the Routine address. For a DPCTraceData event, gets the CodeAddressIndex associated with the Routine address. TraceLoggingEvnetId is a class that manages assigning event IDs (small 64k numbers) to TraceLogging Style events (which don't have them). Because TraceEvent uses EventIDs so fundamentally this deficiency is very problematic. Arguably this should have been done by the ETW system itself. You use it by calling TestForTraceLoggingEventAndFixupIfNeeded on eventRecords. You also have to explicitly call 'Dispose' when you are done with this class. Checks to see if eventRecord has TraceLogging meta data associated with it (EVENT_HEADER_EXT_TYPE_EVENT_SCHEMA_TL) and if so updates EventHeader.Id to be an event ID unique to that provider/opcode/meta-data blob. cleans up native memory allocated by this routine. Checks to see if this event has TraceLogging meta data associated with it (EVENT_HEADER_EXT_TYPE_EVENT_SCHEMA_TL) and if so updates EventHeader.Id to be an event ID unique to that provider/opcode/meta-data blob. given that 'eventRecord' is a TraceLogging event (with meta-data 'metaData'), return a eventID that is unique to that provider/opcode/meta-data blob. ProviderMetaDataKey is what we use to look up TraceLogging meta-data. It is basically just GUID (representing the provider) an opcode (start/stop) and a blob (representing the TraceLogging meta-data for an event) that knows how to compare itself so it can be a key to a hash table. This class encapsulates a single expression of the type ``LeftOperand Operator RightOperand``. - ``LeftOperand`` represents either the name of a property or an event name and a property. The format here is: ``PropertyName`` or ``EventName::PropertyName``. - Acceptable ``Operators`` include < <=, >, >=, !=, = and Contains. - ``RightOperand`` must be either a string or a double. Method responsible for checking if a trace event's contents match the expression. If so, return true, otherwise, return false. Helper method responsible for handling the case when the rhsOperand is a double. Class responsible for encapsulating the collection of FilterQueryExpressions and the logic to combine them to deduce if we match on a particular trace event. NOTE: This class is no way thread-safe. Keep track of the original expression the user provided. This method is responsible for matching the entire user specified expression on an event. Helper methods that implement a modified version of the Shunting Yard Algorithm to convert an expression specified as a infix notation to postfix notation. Method responsible for converting an infix expression into its postfix equivalent. Method that matches the postfix notation The evaluation of a single expression obtained from the PostFix deduction. Method responsible for priming the user specified expression in infix notation to convert into its modified postfix notation. A HistoryDictionary is designed to look up 'handles' (pointer sized quantities), that might get reused over time (eg Process IDs, thread IDs). Thus it takes a handle AND A TIME, and finds the value associated with that handle at that time. Adds the association that 'id' has the value 'value' from 'startTime100ns' ONWARD until it is supersede by the same id being added with a time that is after this. Thus if I did Add(58, 1000, MyValue1), and add(58, 500, MyValue2) 'TryGetValue(58, 750, out val) will return MyValue2 (since that value is 'in force' between time 500 and 1000. Remove all entries associated with a given key (over all time). ZippedETLWriter is a helper class used to compress ETW data (ETL files) along with symbolic information (e.g. NGEN pdbs), as well as other optional metadata (e.g. collection log files), into a single archive ready for transfer to another machine. Declares the intent to write a new ZIP archive that will contain ETW file 'etlFilePath' in it as well as symbolic information (NGEN pdbs) and possibly other information. log is a Text stream to send detailed information to. This routine assumes by default (unless Merge is set to false) that the ETL file needs to be merged before it is archived. It will also generate all the NGEN pdbs needed for the archive. You must call the WriteArchive method before any operations actually happen. Up to that point is is just remembering instructions for WriteArchive to follow. This is the name of the output archive. By default is the same as the ETL file name with a .zip' suffix added (thus it will typically be .etl.zip). If set this is where messages about progress and detailed error information goes. While you dont; have to set this, it is a good idea to do so. By default ZippedETL file will zip the ETL file itself and the NGEN pdbs associated with it. You can add additional files to the archive by calling AddFile. In specififed 'archivePath' is the path in the archive and defaults to just the file name of the original file path. Actually do the work specified by the ZippedETLWriter constructors and other methods. This is the symbol reader that is used to generate the NGEN Pdbs as needed If it is not specififed one is created on the fly. By default the ETL file is merged before being added to the archive. If this is not necessary, you can set this to false. By default there are a number of steps to merging an ETL file. Sometimes, it is desirable to only perform ImageID merging. If desired, set this to true. Uses a compressed format for the ETL file. Normally off. By default the symbol files (PDBs) are included in the ZIP file. If this is not desired for whatever reason, this property can be set to false. Do the work at low priority so as to avoid impacting the system. Normally WriteArchive creates a ZIP archive. However it is possible that you only wish to do the merging and NGEN symbol generation. Setting this property to false will suppress the final ZIP operation. Normally if you ZIP you will delete the original ETL file. Setting this to false overrides this. When merging an ETL for the first time, we might generate some NGEN PDBs and save them as part of the archive. When merging the second time, use this option to make sure that the PDBs that were part of the original archive are included in the new archive. Returns the list of path names to the NGEN pdbs for any NGEN image in 'etlFile' that has any samples in it. ZippedETLReader is a helper class that unpacks the ZIP files generated by the ZippedETLWriter class. It can be smart about placing the symbolic information in these files on the SymbolReader's path so that symbolic lookup 'just works'. Declares the intent to unzip an .ETL.ZIP file that contain an compressed ETL file (and NGEN pdbs) from the archive at 'zipFilePath'. If present, messages about the unpacking go to 'log'. Note that this unpacking only happens when the UnpackArchive() method is called. If set messages about unpacking go here. The name of the ETL file to extract (it is an error if there is not exactly 1). If not present it is derived by changing the extension of the zip archive. Where to put the symbols. After setting any properties to override default behavior, calling this method will actually do the unpacking. A NativeSymbolModule represents symbol information for a native code module. NativeSymbolModules can potentially represent Managed modules (which is why it is a subclass of that interface). NativeSymbolModule should just be the CONTRACT for Native Symbols (some subclass implements it for a particular format like Windows PDBs), however today because we have only one file format we simply implement Windows PDBS here. This can be factored out of this class when we support other formats (e.g. Dwarf). To implmente support for Windows PDBs we use the Debug Interface Access (DIA). See http://msdn.microsoft.com/library/x93ctkx8.aspx for more. I have only exposed what I need, and the interface is quite large (and not super pretty). Returns the name of the type allocated for a given relative virtual address. Returns null if the given rva does not match a known heap allocation site. Finds a (method) symbolic name for a given relative virtual address of some code. Returns an empty string if a name could not be found. Finds a (method) symbolic name for a given relative virtual address of some code. Returns an empty string if a name could not be found. symbolStartRva is set to the start of the symbol start Fetches the source location (line number and file), given the relative virtual address (RVA) of the location in the executable. This overload of SourceLocationForRva like the one that takes only an RVA will return a source location if it can. However this version has additional support for NGEN images. In the case of NGEN images for .NET V4.6.1 or later), the NGEN images can't convert all the way back to a source location, but they can convert the RVA back to IL artifacts (ilAssemblyName, methodMetadataToken, iloffset). THese can then be used to look up the source line using the IL PDB. Thus if the return value from this is null, check to see if the ilAssemblyName is non-null, and if not you can look up the source location using that information. Managed code is shipped as IL, so RVA to NATIVE mapping can't be placed in the PDB. Instead what is placed in the PDB is a mapping from a method's meta-data token and IL offset to source line number. Thus if you have a metadata token and IL offset, you can again get a source location The symbol representing the module as a whole. All global symbols are children of this symbol The a unique identifier that is used to relate the DLL and its PDB. Along with the PdbGuid, there is a small integer call the age is also used to find the PDB (it represents the different post link transformations the DLL has undergone). A source file represents a source file from a PDB. This is not just a string because the file has a build time path, a checksum, and it needs to be 'smart' to copy down the file if requested. TODO We don't need this subclass. We can have SourceFile simply a container that holds the BuildTimePath, hashType and hashValue. The lookup of the source can then be put on NativeSymbolModule and called from SourceFile generically. This makes the different symbol files more similar and is a nice simplification. Try to fetch the source file associated with 'buildTimeFilePath' from the symbol server information from the PDB from 'pdbPath'. Will return a path to the returned file (uses SourceCacheDirectory associated symbol reader for context where to put the file), or null if unsuccessful. There is a tool called pdbstr associated with srcsrv that basically does this. pdbstr -r -s:srcsrv -p:PDBPATH will dump it. The basic flow is There is a variables section and a files section The file section is a list of items separated by *. The first is the path, the rest are up to you You form a command by using the SRCSRVTRG variable and substituting variables %var1 where var1 is the first item in the * separated list There are special operators %fnfile%(XXX), etc that manipulate the string XXX (get file name, translate \ to / ... If what is at the end is a valid URL it is looked up. Parse the 'srcsrv' stream in a PDB file and return the target for SourceFile represented by the 'this' pointer. This target is iether a ULR or a local file path. You can dump the srcsrv stream using a tool called pdbstr pdbstr -r -s:srcsrv -p:PDBPATH The target in this stream is called SRCSRVTRG and there is another variable SRCSRVCMD which represents the command to run to fetch the soruce into SRCSRVTRG To form the target, the stream expect you to private a %targ% variable which is a directory prefix to tell where to put the source file being fetched. If the source file is available via a URL this variable is not needed. ********* This is a typical example of what is in a PDB with source server information. SRCSRV: ini ------------------------------------------------ VERSION=3 INDEXVERSION=2 VERCTRL=Team Foundation Server DATETIME=Thu Mar 10 16:15:55 2016 SRCSRV: variables ------------------------------------------ TFS_EXTRACT_CMD=tf.exe view /version:%var4% /noprompt "$%var3%" /server:%fnvar%(%var2%) /output:%srcsrvtrg% TFS_EXTRACT_TARGET=%targ%\%var2%%fnbksl%(%var3%)\%var4%\%fnfile%(%var1%) VSTFDEVDIV_DEVDIV2=http://vstfdevdiv.redmond.corp.microsoft.com:8080/DevDiv2 SRCSRVVERCTRL=tfs SRCSRVERRDESC=access SRCSRVERRVAR=var2 SRCSRVTRG=%TFS_extract_target% SRCSRVCMD=%TFS_extract_cmd% SRCSRV: source files --------------------------------- ------ f:\dd\externalapis\legacy\vctools\vc12\inc\cvconst.h*VSTFDEVDIV_DEVDIV2*/DevDiv/Fx/Rel/NetFxRel3Stage/externalapis/legacy/vctools/vc12/inc/cvconst.h*1363200 f:\dd\externalapis\legacy\vctools\vc12\inc\cvinfo.h*VSTFDEVDIV_DEVDIV2*/DevDiv/Fx/Rel/NetFxRel3Stage/externalapis/legacy/vctools/vc12/inc/cvinfo.h*1363200 f:\dd\externalapis\legacy\vctools\vc12\inc\vc\ammintrin.h*VSTFDEVDIV_DEVDIV2*/DevDiv/Fx/Rel/NetFxRel3Stage/externalapis/legacy/vctools/vc12/inc/vc/ammintrin.h*1363200 SRCSRV: end ------------------------------------------------ ********* And here is a more modern one where the source code is available via a URL. SRCSRV: ini ------------------------------------------------ VERSION=2 INDEXVERSION=2 VERCTRL=http SRCSRV: variables ------------------------------------------ SRCSRVTRG=https://nuget.smbsrc.net/src/%fnfile%(%var1%)/%var2%/%fnfile%(%var1%) SRCSRVCMD= SRCSRVVERCTRL=http SRCSRV: source files --------------------------------------- c:\Users\rafalkrynski\Documents\Visual Studio 2012\Projects\DavidSymbolSourceTest\DavidSymbolSourceTest\Demo.cs*SQPvxWBMtvANyCp8Pd3OjoZEUgpKvjDVIY1WbaiFPMw= SRCSRV: end ------------------------------------------------ returns the target source file path returns the command to fetch the target source file Specify the value for %targ% variable. This is the directory where source files can be fetched to. Typically the returned file is under this directory If the value is null, %targ% variable be emtpy. This assumes that the resulting file is something that does not need to be copied to the machine (either a URL or a file that already exists) Returns the location of the tf.exe executable or Gets the 'srcsvc' data stream from the PDB and return it in as a string. Returns null if it is not present. There is a tool called pdbstr associated with srcsrv that basically does this. pdbstr -r -s:srcsrv -p:PDBPATH will dump it. For Project N modules it returns the list of pre merged IL assemblies and the corresponding mapping. For ProjectN modules, gets the merged IL image embedded in the .PDB (only valid for single-file compilation) For ProjectN modules, gets the pseudo-assembly embedded in the .PDB, if there is one. For ProjectN modules, gets the binary blob that describes the mapping from RVAs to methods. For ProjectN modules, gets the binary blob that describes the mapping from RVAs to types. This function checks if the SymbolModule is disposed before proceeding with the call. This is important because DIA doesn't provide any guarantees as to what will happen if one attempts to call after the session is disposed, so this at least ensure that we fail cleanly in non-concurrent cases. This static class contains the GetTypeName method for retrieving the type name of a heap allocation site. See https://github.com/KirillOsenkov/Dia2Dump/blob/master/PrintSymbol.cpp for more details Represents a single symbol in a PDB file. The name for the symbol The relative virtual address (offset from the image base when loaded in memory) of the symbol The length of the memory that the symbol represents. A small integer identifier tat is unique for that symbol in the DLL. Decorated names are names that most closely resemble the source code (have overloading). However when the linker does not directly support all the expressiveness of the source language names are encoded to represent this. This return this encoded name. Returns true if the two symbols live in the same linker section (e.g. text, data ...) Returns the children of the symbol. Will return null if there are no children. Returns the children of the symbol, with the given tag. Will return null if there are no children. Compares the symbol by their relative virtual address (RVA) override SymPath is a class that knows how to parse _NT_SYMBOL_PATH syntax. This allows you to set the _NT_SYMBOL_PATH as a from the windows environment. This 'cleans up' a symbol path. In particular Empty ones are replaced with good defaults (symweb or msdl) All symbol server specs have local caches (%Temp%\SymbolCache if nothing else is specified). Note that this routine does NOT update _NT_SYMBOL_PATH. Returns the string representing a symbol path for the 'standard' Microsoft symbol servers. This returns the public msdl.microsoft.com server if outside Microsoft. Create an empty symbol path Create a symbol that represents 'path' (the standard semicolon separated list of locations) Returns the List of elements in the symbol path. Append all the elements in the semicolon separated list, 'path', to the symbol path represented by 'this'. returns the 'this' pointer append a new symbol path element to the beginning of the symbol path represented by 'this'. returns the 'this' pointer insert all the elements in the semicolon separated list, 'path' to the beginning of the symbol path represented by 'this'. returns the 'this' pointer insert a new symbol path element to the beginning of the symbol path represented by 'this'. returns the 'this' pointer If you need to cache files locally, put them here. It is defined to be the first local path of a SRV* qualification or %TEMP%\SymbolCache if not is present. People can use symbol servers without a local cache. This is bad, add one if necessary. Removes all references to remote paths. This ensures that network issues don't cause grief. Create a new symbol path which first search all machine local locations (either explicit location or symbol server cache locations) followed by all non-local symbol server. This produces better behavior (If you can find it locally it will be fast) Returns the string representation (semicolon separated) for the symbol path. Writes an XML representation of the symbol path to 'writer' Checks to see 'computerName' exists (there is a Domain Names Service (DNS) reply to it) This routine times out relative quickly (after 700 msec) if there is a problem reaching the computer, and returns false. This is the backing field for the lazily-computed property. SymPathElement represents the text between the semicolons in a symbol path. It can be a symbol server specification or a simple directory path. SymPathElement follows functional conventions. After construction everything is read-only. Returns true if this element of the symbol server path a symbol server specification Returns the local cache for a symbol server specification. returns null if not specified Returns location to look for symbols. This is either a directory specification or an URL (for symbol servers) This can be null if it is not specified (for cache-only paths). IsRemote returns true if it looks like the target is not on the local machine. Returns the string repsentation for the symbol server path element (e.g. SRV*c:\temp*\\symbols\symbols) Implements object interface Implements object interface A symbol reader represents something that can FIND pdbs (either on a symbol server or via a symbol path) Its job is to find a full path a PDB. Then you can use OpenSymbolFile to get a SymbolReaderModule and do more. Opens a new SymbolReader. All diagnostics messages about symbol lookup go to 'log'. Optional HttpClient delegating handler to be used when downloading symbols or source files. Note: The delegating handler will be disposed when this SymbolReader is disposed. Finds the symbol file for 'exeFilePath' that exists on the current machine (we open it to find the needed info). Uses the SymbolReader.SymbolPath (including Symbol servers) to look up the PDB, and will download the PDB to the local cache if necessary. It will also generate NGEN pdbs into the local symbol cache unless SymbolReaderFlags.NoNGenPDB is set. By default for NGEN images it returns the NGEN pdb. However if 'ilPDB' is true it returns the IL PDB. Returns null if the pdb can't be found. Find the complete PDB path, given just the simple name (filename + pdb extension) as well as its 'signature', which uniquely identifies it (on symbol servers). Uses the SymbolReader.SymbolPath (including Symbol servers) to look up the PDB, and will download the PDB to the local cache if necessary. A Guid of Empty, means 'unknown' and will match the first PDB that matches simple name. Thus it is unsafe. Returns null if the PDB could not be found The name of the PDB file (we only use the file name part) The GUID that is embedded in the DLL in the debug information that allows matching the DLL and the PDB Tools like BBT transform a DLL into another DLL (with the same GUID) the 'pdbAge' is a small integers that indicates how many transformations were done If you know the path to the DLL for this pdb add it here. That way we can probe next to the DLL for the PDB file. This is an optional string that identifies the file version (the 'Version' resource information. It is used only to provided better error messages for the log. This API looks up an executable file, by its build-timestamp and size (on a symbol server), 'fileName' should be a simple name (no directory), and you need the buildTimeStamp and sizeOfImage that are found in the PE header. Returns null if it cannot find anything. Given the path name to a particular PDB file, load it so that you can resolve symbols in it. The name of the PDB file to open. The SymbolReaderModule that represents the information in the symbol file (PDB) Like OpenSymbolFile, which opens a PDB, but this version will fail (return null) if it is not WindowsSymbolModule. It is a shortcut for OpenSymbolFile as NativeSymbolModule The symbol path used to look up PDB symbol files. Set when the reader is initialized. The paths used to look up source files. defaults to _NT_SOURCE_PATH. Where symbols are downloaded if needed. Derived from symbol path. It is the first directory on the local machine in a SRV*DIR*LOC spec, and %TEMP%\SymbolCache otherwise. The place where source is downloaded from a source server. Is this symbol reader limited to just the local machine cache or not? We call back on this when we find a PDB by probing in 'unsafe' locations (like next to the EXE or in the Built location) If this function returns true, we assume that it is OK to use the PDB. If set OnSymbolFileFound will be called when a PDB file is found. It is passed the complete local file path, the PDB Guid (may be Guid.Empty) and PDB age. A place to log additional messages Given a full filename path to an NGEN image, ensure that there is an NGEN image for it in the symbol cache. If one already exists, this method simply returns that. If not it is generated and placed in the symbol cache. When generating the PDB this routine attempt to resolve line numbers, which DOES require looking up the PDB for the IL image. Thus routine may do network accesses (to download IL PDBs). Note that FindSymbolFilePathForModule calls this, so normally you don't need to call this method directly. By default it places the PDB in the SymbolCacheDirectory using normal symbol server cache conventions (PDBNAME\Guid-AGE\Name). You can override this by specifying the outputDirectory parameter. The full path name of the PDB generated for the NGEN image. Given a NGEN (or ReadyToRun) imge 'ngenImageFullPath' and the PDB path that we WANT it to generate generate the PDB. Returns either pdbPath on success or null on failure. TODO can be removed when we properly publish the NGEN pdbs as part of build. Called when you are done with the symbol reader. Closes all opened symbol files. Returns true if 'filePath' exists and is a PDB that has pdbGuid and pdbAge. if pdbGuid == Guid.Empty, then the pdbGuid and pdbAge checks are skipped. Fetches a file from the server 'serverPath' with pdb signature path 'pdbSigPath' (concatinate them with a / or \ separator to form a complete URL or path name). It will place the file in 'fullDestPath' It will return true if successful If 'contentTypeFilter is present, this predicate is called with the URL content type (e.g. application/octet-stream) and if it returns false, it fails. This ensures that things that are the wrong content type (e.g. redirects to some sort of login) fail cleanly. You should probably be using GetFileFromServer path to server (e.g. \\symbols\symbols or http://symweb) pdb path with signature (e.g clr.pdb/1E18F3E494DC464B943EA90F23E256432/clr.pdb) the full path of where to put the file locally if present this allows you to filter out urls that dont match this ContentType. Build the full uri from server path and pdb index path This just copies a stream to a file path with logging. Looks up 'fileIndexPath' on the server 'urlForServer' (concatenate to form complete URL) copying the file to 'targetPath' and returning targetPath name there (thus it is always a local file). Unlike GetPhysicalFileFromServer, GetFileFromServer understands how to deal with compressed files and file.ptr (redirection). targetPath or null if the file cannot be found. Deduce the path to where CLR.dll (and in particular NGEN.exe live for the NGEN image 'ngenImagepath') Returns null if it can't be found. If the NGEN image is associated with a private runtime return that value in 'privateVerStr' We may be a 32 bit app which has File system redirection turned on Morph System32 to SysNative in that case to bypass file system redirection A SymbolModule represents a file that contains symbolic information (a Windows PDB or Portable PDB). This is the interface that is independent of what kind of symbolic file format you use. Becase portable PDBs only support managed code, this shared interface is by necessity the interface for managed code only (currently only Windows PDBs support native code). This is the EXE associated with the Pdb. It may be null or an invalid path. It is used to help look up source code (it is implicitly part of the Source Path search) The path name to the PDB itself. Might be empty if the symbol information is in memory. The Guid that is used to uniquely identify the DLL-PDB pair (used for symbol servers) Fetches the SymbolReader associated with this SymbolModule. This is where shared attributes (like SourcePath, SymbolPath etc) are found. Given a method and an IL offset, return a source location (line number and file). Returns null if it could not find it. If the symbol file format supports SourceLink JSON this routine should be overriden to return it. Return a URL for 'buildTimeFilePath' using the source link mapping (that 'GetSourceLinkJson' fetched) Returns null if there is URL using the SourceLink The path to the source file at build time The source link URL true if a source link file could be found Parses SourceLink information and returns a list of filepath -> url Prefix tuples. A SourceLocation represents a point in the source code. That is the file and the line number. The source file for the code The starting line number for the code. The ending line number for the code. The starting column number for the code. This column corresponds to the starting line number. The ending column number for the code. This column corresponds to the ending line number. SymbolReaderFlags indicates preferences on how aggressively symbols should be looked up. No options this is the common case, where you want to look up everything you can. Only fetch the PDB if it lives in the symbolCacheDirectory (is local an is generated). This will generate NGEN pdbs unless the NoNGenPDBs flag is set. No NGEN PDB generation. The path of the file at the time the source file was built. We also look here when looking for the source. If the source file is directly available on the web (that is there is a Url that can be used to fetch it with HTTP Get), then return that Url. If no such publishing point exists this property will return null. This may fetch things from the source server, and thus can be very slow, which is why it is not a property. returns a path to the file on the local machine (often in some machine local cache). If requireChecksumMatch == false then you can see if you have an exact match by calling ChecksumMatches (and if there is a checksum with HasChecksum). true if the PDB has a checksum for the data in the source file. Gets the name of the algorithm used to compute the source file hash. Values should be from System.Security.Cryptography.HashAlgorithmName. This is null if there is no checksum. Gets the bytes of the source files checksum. This is null if there is no checksum. If GetSourceFile is called and 'requireChecksumMatch' == false then you can call this property to determine if the checksum actually matched or not. This will return true if the original PDB does not have a checksum (HasChecksum == false) ; Obtains information used to download the source file file source link The URL to hit to download the source file relative file path for the Source Link entry. For example, if the SourceLink map contains 'C:\foo\*' and this maps to 'C:\foo\bar\baz.cs', the relativeFilePath is 'bar\baz.cs'. For absolute SourceLink mappings, relativeFilePath will simply be the name of the file. true if SourceLink info can be found for this file Look up the source from the source server. Returns null if it can't find the source By default this simply uses the Url to look it up on the web. If 'Url' returns null so does this. Given 'fileName' which is a path to a file (which may not exist), set _filePath and _checksumMatches appropriately. Namely _filePath should always be the 'best' candidate for the source file path (matching checksum wins, otherwise first existing file wins). Returns true if we have a perfect match (no additional probing needed). Returns true if 'filePath' matches the checksum OR we don't have a checkdum (thus if we pass what validity check we have). The different line endings we support for computing file hashes. Convert an input file path from a device path to a volume-based path. Example input: \device\harddiskvolume7\sdk\shared\microsoft.netcore.app\3.1.7\coreclr.dll Example output: \\?\Volume{a296af82-8d67-4f46-a792-9e78ec0adf9b}\sdk\shared\microsoft.netcore.app\3.1.7\coreclr.dll Disable the AppContextSwitch "UseLegacyPathHandling", as legacy path handling doesn't support usage of volume-based paths. This is done via reflection because PerfView and TraceEvent target .NET 4.5 which doesn't have access to AppContext. If this is run on a .NET 4.5 runtime, it will silently fail, but it's unlikely that anyone that needs this functionality for container support is going to be running .NET 4.5. General purpose utilities dealing with archiveFile system directories. SafeCopy sourceDirectory to directoryToVersion recursively. The target directory does no need to exist SafeCopy all files from sourceDirectory to directoryToVersion. If searchOptions == AllDirectories then the copy is recursive, otherwise it is just one level. The target directory does not need to exist. Clean is sort of a 'safe' recursive delete of a directory. It either deletes the files or moves them to '*.deleting' names. It deletes directories that are completely empty. Thus it will do a recursive delete when that is possible. There will only be *.deleting files after this returns. It returns the number of files and directories that could not be deleted. Removes the oldest directories directly under 'directoryPath' so that only 'numberToKeep' are left. Directory to removed old files from. The number of files to keep. true if there were no errors deleting files DirectoryUtilities.GetFiles is basically the same as Directory.GetFiles however it returns IEnumerator, which means that it lazy. This is very important for large directory trees. A searchPattern can be specified (Windows wildcard conventions) that can be used to filter the set of archiveFile names returned. Suggested Usage foreach(string fileName in DirectoryUtilities.GetFiles("c:\", "*.txt")){ Console.WriteLine(fileName); } The base directory to enumerate A pattern to filter the names (windows filename wildcards * ?) Indicate if the search is recursive or not. The enumerator for all archiveFile names in the directory (recursively). Returns a lazy enumerable for every path in 'directoryName' that matchs 'searchPattern' (default is *)MO General purpose utilities dealing with archiveFile system files. GetLines works much like File.ReadAllLines, however instead of returning a array of lines, it returns a IEnumerable so that the archiveFile is not read all at once. This allows 'foreach' syntax to be used on very large files. Suggested Usage foreach(string lineNumber in FileUtilities.GetLines("largeFile.txt")){ Console.WriteLine(lineNumber); } The base directory to enumerate. The enumerator for all lines in the archiveFile. Given archiveFile specifications possibly with wildcards in them Returns an enumerator that returns each expanded archiveFile name in turn. If searchOpt is AllDirectories it does a recursive match. Delete works much like File.Delete, except that it will succeed if the archiveFile does not exist, and will rename the archiveFile so that even if the archiveFile is locked the original archiveFile variable will be made available. It renames the archiveFile with a '[num].deleting'. These files might be left behind. It returns true if it was completely successful. If there is a *.deleting archiveFile left behind, it returns false. The variable of the archiveFile to delete Try to delete 'fileName' catching any exception. Returns true if successful. It will delete read-only files. SafeCopy sourceFile to destinationFile. If the destination exists used ForceDelete to get rid of it first. Moves sourceFile to destinationFile. If the destination exists used ForceDelete to get rid of it first. Returns true if the two file have exactly the same content (as a stream of bytes). Utilities associated with file name paths. Given a path and a superdirectory path relativeToDirectory compute the relative path (the path from) relativeToDirectory General utilities associated with streams. Open the 'fromFilePath' and write its contents to 'toStream' Open the 'toFilePath' for writing and write the contents of 'fromStream' to it CopyStream simply copies 'fromStream' to 'toStream' The important thing about these general utilities is that they have only dependencies on mscorlib and System (they can be used from anywhere). Given an XML element, remove the closing operator for it, so you can add new child elements to it by concatination. Given an object 'obj' do ToString() on it, and then transform it so that all speical XML characters are escaped and return the result. If 'quote' is true also surround the resulting object with double quotes. A shortcut for XmlEscape(obj, true) (that is ToString the object, escape XML chars, and then surround with double quotes. Create a doubly quoted string for the decimal integer value Create a double quoted string for the hexidecimal value of 'value' Create a double quoted string for the hexidecimal value of 'value' Create a double quoted string for the hexidecimal value of 'value' Create a double quoted string for the hexidecimal value of 'value' Used to send the rawManifest into the event stream as a series of events. Finds native DLLS next to the managed DLL that uses them. ManifestModule.FullyQualifiedName returns this as file path if the assembly is loaded as byte array Loads a native DLL with a filename-extension of 'simpleName' by adding the path of the currently executing assembly Gets the name of the directory containing compiled binaries (DLLs) which have the same architecture as the currently executing process. This is the backing field for the lazily-computed property. A StackSource that aggregates information from other StackSources into a single unified view. Each StackSource has a name associated with it. The stacks for each StackSource will be grouped under a pseudo-frame named the same as the source name. Source names are specified on initialization. Initialize a new AggregateStackSource. An IEnumerable of KeyValuePairs mapping source names to StackSources. Enumerate samples with a callback function. The function to call on each sample. override Enumerate samples for a given set of scenarios with a callback function. The function to call on each sample. An array of length ScenarioCount. If scenariosIncluded[i] == true, include scenario i. Override Look up a sample by index. The index of the sample to look up. The sample, if it can be found and all sub-sources support indexing; null otherwise. Gets the index of the caller of a given call stack. The call stack to look up. The caller, if it exists, otherwise. Get the frame index of a given call stack. The call stack to look up. The frame index of the call stack, if it exists, otherwise. Gets the name of a frame. The frame to look up. Whether to include full module paths. The name of the frame. The total number of call stacks in this source. The total number of frames in this source. The total number of samples in this source. The names for the scenarios. override override Convert a StackSourceSample produced by a sub-source into one suitable for the aggregate source. The StackSourceSample to convert. A place to but the returned sampled (will become the return value). The index of the source from which the sample came. The converted sample. If ConvertSample is called again, all previous samples produced by ConvertSample may no longer be used. Friendly names of sources. Name 0 is the name of the pseudo-source, which should not be used. The list of sources. Source 0 is the pseudo-source (identical to m_pseudo). THis is the time of the first sample. It lets us normalize the time in the sample to be relative to this. A StackSource to generate the pseudo-frames needed to group scenarios. Initialize a new PseudoStackSource. The names of the frames. Gets the CallStackIndex of the call stack corresponding to a given source. The index of the source to look up. The StackSourceCallStackIndex of a stack under which to group all call stacks for that source. Gets the index of the caller of a given call stack. The call stack to look up. The caller, if it exists, otherwise. Get the frame index of a given call stack. The call stack to look up. The frame index of the call stack, if it exists, otherwise. Gets the name of a frame. The frame to look up. Whether to include full module paths. The name of the frame. The total number of call stacks in this source. The total number of frames in this source. The names of the frames that this source generates. Extension methods for type-safe IndexMap operations on StackSource*Index enums. This is just a class that holds data. It does nothing except support an 'update' events Constructs a Filter parameter class with all empty properties. Create a Filter Parameters Structure form another one Set a Filter Parameters Structure form another one Fetch Name Fetch StartTimeRelativeMSec Fetch EndTimeRelativeMSec Fetch MinInclusiveTimePercent Fetch FoldRegExs Fetch IncludeRegExs Fetch ExcludeRegExs Fetch GroupRegExs Fetch TypePriority Fetch ScenarioList Fetch Scenarios override override TODO Document Write out the FilterParameters to XML 'writer' Create an XML representation of FilterParams as a string A FilterStackSouce morphs one stack filters or groups the stacks of one stack source to form a new stack source. It is very powerful mechanism. Create a new FilterStackSource. Specifies how to filter or group the stacks The input source to morph How to scale the data (as time or simply by size of data) Override Override override Override Override Override Override Override Override Override Override Override Override Override Associated with every frame is a FrameInfo which is the computed answers associated with that frame name. We cache these and so most of the time looking up frame information is just an array lookup. FrameInfo contains information that is ONLY dependent on the frame name (not the stack it came from), so entry point groups and include patterns can not be completely processed at this point. Never returns null. Generate the stack information for 'stack' and place it in stackInfoRet. Only called by GetStackInfo. Returns the frame information for frameIndex. Never returns null. This is just the parsed form of a grouping specification Pat->GroupNameTemplate (it has a pattern regular expression and a group name that can have replacements) It is a trivial class Experimentally we are going to special case the module entry pattern. Parses a string into the GroupPattern structure that allows it to executed (matched). Given the name of a frame, look it up in the group patterns and morph it to its group name. If the group that matches is a entryGroup then set 'isEntryGroup'. Will return null if no group matches 'frameName' Holds parsed information about patterns for groups includes, excludes or folds. Returns the index in the 'pats' array of the first pattern that matches 'str'. Returns -1 if no match. returns true if set1 and set1 (as returned from MatchSet) are identical Convert a string from my regular expression format (where you only have * and { } as grouping operators and convert them to .NET regular expressions string FrameInfo is all the information we need to associate with an Frame ID (to figure out what group/pattern it belongs to) This includes what group it belongs to, the include patterns it matches whether to discard or fold it. It is all the processing we can do with JUST the frame ID. Note that FrameInfo is reused by multiple stacks, which means that you should NOT update fields in it after initial creation. This is what we return to the Stack crawler, it encodes either that we should filter the sample, fold the frame, form a group, or the frameID that we have chosen to represent the group as a whole. Represents all accumulated information about grouping for a particular stack. Effectively this is the 'result' of applying the grouping and filtering to a particular stack. We cache the last 100 or so of these because stacks tend to reuse the parts of the stack close the root. The include patterns that have been matched by some frame in this stack. (ultimately we need all bits set). Can be null, which means the empty set. Represents a frame that does not match any pattern. Thus the default of simply returning the frame ID is appropriate Represents a frame that should be discarded. Represents a frame that should be folded into its caller. We cache information about stacks we have previously seen so we can short-circuit work. TODO make dynamic. Note when this value is 4096 some memory profiles are VERY sluggish. Don't make it too small unless it is adaptive. A class that maps contiguous indices from various sources from and to a single range of contiguous indices. This is useful for aggregating indices used, for instance, in the interface for StackSource (StackSourceCallStackIndex / StackSourceFrameIndex) in AggregateStackSource. This is an easy way, given the incoming StackSource*Index, to find the aggregated source to query, and the corresponding StackSource*Index to send to the source. With counts [3, 7, 5]: 1 1 1 1 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 = Incoming index __0__ ______1______ ____2____ = Source number 0 1 2|0 1 2 3 4 5 6|0 1 2 3 4 = Offset Initialize a new IndexMap with the specified counts. A list mapping an index to its corresponding count. Find the source for an index. The aggregate index to look up. The source that belongs to. Find the offset into a given source of a given aggregate index. The aggregate index to look up. The source to find the offset into. The offset of into . Finds the index for a given source/offset pair. The source number of the item. The offset into the corresponding source for the item. The index corresponding to the pair of and . The total number of indices in the map. The lookup table to convert indices to source/offset pairs. This contains the cumulative count of indices that occurred before each source. The last element is the total number of indices (equal to m_range). The total number of indices in the map. We remember the last source we looked up and check there first very likely they are next to one another. A finite cache based with a least recently used algorithm for replacement. It is meant to be fast (fast as a hashtable), and space efficient (not much over the MaxEntry key-value pairs are stored. (only 8 bytes per entry additional). After reaching MaxEntry entries. It uses a roughly least-recently used algorithm to pick a entry to recycle. To stay efficient it only searches a finite time (up to 5 entries) for a entry that is older than 1/2 of the entries in the table. It has the property that if you are in the maxEntries/2 most commonly fetched things, you very unlikely to be evicted once you are in the cache. maxEntries currently is only set in the constructor. Thus this is a finite sized cache but is otherwise very efficient. Currently it uses ushorts internally so the number of entries is limited to 64K (it silently limits it if you give maxEntries > 64K). Fetches the value from the cache with key 'key'. Returns default(T) if not present Fetches the value from the cache with key 'key'. Returns false if not present. Adds 'key' with value 'value' to the cache. Removes all entries in the cache. Sets the maxiumum number of key-value pairs the cache will keep. (after that old ones are remvoed). Represents a null pointer (end of a linked list) CommandOptions is a helper class for the Command class. It stores options that affect the behavior of the execution of ETWCommands and is passes as a parameter to the constructor of a Command. It is useful for these options be be on a separate class (rather than on Command itself), because it is reasonably common to want to have a set of options passed to several commands, which is not easily possible otherwise. Can be assigned to the Timeout Property to indicate infinite timeout. CommanOptions holds a set of options that can be passed to the constructor to the Command Class as well as Command.Run* Return a copy an existing set of command options The copy of the command options Normally commands will throw if the subprocess returns a non-zero exit code. NoThrow suppresses this. Updates the NoThrow propery and returns the updated commandOptions. Updated command options ShortHand for UseShellExecute and NoWait Updates the Start propery and returns the updated commandOptions. Normally commands are launched with CreateProcess. However it is also possible use the Shell Start API. This causes Command to look up the executable differently Updates the Start propery and returns the updated commandOptions. Indicates that you want to hide any new window created. Updates the NoWindow propery and returns the updated commandOptions. Indicates that you want don't want to wait for the command to complete. Updates the NoWait propery and returns the updated commandOptions. Indicates that the command must run at elevated Windows privledges (causes a new command window) Updates the Elevate propery and returns the updated commandOptions. By default commands have a 10 minute timeout (600,000 msec), If this is inappropriate, the Timeout property can change this. Like all timouts in .NET, it is in units of milliseconds, and you can use CommandOptions.Infinite to indicate no timeout. Updates the Timeout propery and returns the updated commandOptions. CommandOptions.Infinite can be used for infinite Indicates the string will be sent to Console.In for the subprocess. Updates the Input propery and returns the updated commandOptions. Indicates the current directory the subProcess will have. Updates the CurrentDirectory propery and returns the updated commandOptions. Indicates the standard output and error of the command should be redirected to a archiveFile rather than being stored in Memory in the 'Output' property of the command. Updates the OutputFile propery and returns the updated commandOptions. Indicates the standard output and error of the command should be redirected to a a TextWriter rather than being stored in Memory in the 'Output' property of the command. Updates the OutputStream property and returns the updated commandOptions. Gets the Environment variables that will be set in the subprocess that differ from current process's environment variables. Any time a string of the form %VAR% is found in a value of a environment variable it is replaced with the value of the environment variable at the time the command is launched. This is useful for example to update the PATH environment variable eg. "%PATH%;someNewPath" Adds the environment variable with the give value to the set of environmetn variables to be passed to the sub-process and returns the updated commandOptions. Any time a string of the form %VAR% is found in a value of a environment variable it is replaced with the value of the environment variable at the time the command is launched. This is useful for example to update the PATH environment variable eg. "%PATH%;someNewPath" Command represents a running of a command lineNumber process. It is basically a wrapper over System.Diagnostics.Process, which hides the complexitity of System.Diagnostics.Process, and knows how to capture output and otherwise makes calling commands very easy. The time the process started. Returns true if the process has exited. The time the processed Exited. (HasExited should be true before calling) The duration of the command (HasExited should be true before calling) The operating system ID for the subprocess. The process exit code for the subprocess. (HasExited should be true before calling) Often this does not need to be checked because Command.Run will throw an exception if it is not zero. However it is useful if the CommandOptions.NoThrow property was set. The standard output and standard error output from the command. This is accumulated in real time so it can vary if the process is still running. This property is NOT available if the CommandOptions.OutputFile or CommandOptions.OutputStream is specified since the output is being redirected there. If a large amount of output is expected (> 1Meg), the Run.AddOutputStream(Stream) is recommended for retrieving it since the large string is never materialized at one time. Returns that CommandOptions structure that holds all the options that affect the running of the command (like Timeout, Input ...) Run 'commandLine', sending the output to the console, and wait for the command to complete. This simulates what batch filedo when executing their commands. It is a bit more verbose by default, however The command lineNumber to run as a subprocess Additional qualifiers that control how the process is run A Command structure that can be queried to determine ExitCode, Output, etc. Run 'commandLine' as a subprocess and waits for the command to complete. Output is captured and placed in the 'Output' property of the returned Command structure. The command lineNumber to run as a subprocess Additional qualifiers that control how the process is run A Command structure that can be queried to determine ExitCode, Output, etc. Launch a new command and returns the Command object that can be used to monitor the restult. It does not wait for the command to complete, however you can call 'Wait' to do that, or use the 'Run' or 'RunToConsole' methods. */ The command lineNumber to run as a subprocess Additional qualifiers that control how the process is run A Command structure that can be queried to determine ExitCode, Output, etc. Create a subprocess to run 'commandLine' with no special options. The command lineNumber to run as a subprocess Wait for a started process to complete (HasExited will be true on return) Wait returns that 'this' pointer. Throw a error if the command exited with a non-zero exit code printing useful diagnostic information along with the thrown message. This is useful when NoThrow is specified, and after post-processing you determine that the command really did fail, and an normal Command.Run failure was the appropriate action. An additional message to print in the throw (can be null) Get the underlying process object. Generally not used. Kill the process (and any child processses (recursively) associated with the running command). Note that it may not be able to kill everything it should if the child-parent' chain is broken by a child that creates a subprocess and then dies itself. This is reasonably uncommon, however. Put double quotes around 'str' if necessary (handles quotes quotes. Given a string 'commandExe' look for it on the path the way cmd.exe would. Returns null if it was not found. requiredOSVersion is a number that is the major version * 10 + minor. Thus Win 10 == 100 Win 8 == 62 Win 7 == 61 Vista == 60 This returns true if true OS version is >= 'requiredOSVersion The DiaLoader class knows how to load the msdia140.dll (the Debug Access Interface) (see docs at http://msdn.microsoft.com/en-us/library/x93ctkx8.aspx), without it being registered as a COM object. Basically it just called the DllGetClassObject interface directly. It has one public method 'GetDiaSourceObject' which knows how to create a IDiaDataSource object. From there you can do anything you need. In order to get IDiaDataSource3 which includes'getStreamSize' API, you need to use the vctools\langapi\idl\dia2_internal.idl file from devdiv to produce Dia2Lib.dll roughly what you need to do is copy vctools\langapi\idl\dia2_internal.idl . copy vctools\langapi\idl\dia2.idl . copy vctools\langapi\include\cvconst.h . Change dia2.idl to include interface IDiaDataSource3 inside library Dia2Lib->importlib->coclass DiaSource midl dia2_internal.idl /D CC_DP_CXX tlbimp dia2_internal.tlb REM result is Dia2Lib.dll Load the msdia100 dll and get a IDiaDataSource from it. This is your gateway to PDB reading. Used to ensure the native library is loaded at least once prior to trying to use it. No protection is included to avoid multiple loads, but this is not a problem since we aren't trying to unload the library after use. PEFile is a reader for the information in a Portable Exectable (PE) FILE. This is what EXEs and DLLs are. It can read both 32 and 64 bit PE files. Create a new PEFile header reader that inspects the The Header for the PE file. This contains the infor in a link /dump /headers Looks up the debug signature information in the EXE. Returns true and sets the parameters if it is found. If 'first' is true then the first entry is returned, otherwise (by default) the last entry is used (this is what debuggers do today). Thus NGEN images put the IL PDB last (which means debuggers pick up that one), but we can set it to 'first' if we want the NGEN PDB. Gets the File Version Information that is stored as a resource in the PE file. (This is what the version tab a file's property page is populated with). For side by side dlls, the manifest that describes the binding information is stored as the RT_MANIFEST resource, and it is an XML string. This routine returns this. Returns true if this is and NGEN or Ready-to-Run image (it has precompiled native code) Returns true if file has a managed ready-to-run image. Gets the major and minor ready-to-run version. returns true if ready-to-run. Closes any file handles and cleans up resources. A PEHeader is a reader of the data at the beginning of a PEFile. If the header bytes of a PEFile are read or mapped into memory, this class can parse it when given a poitner to it. It can read both 32 and 64 bit PE files. Returns a PEHeader for void* pointer in memory. It does NO validity checking. The total s,ize of the header, including section array of the the PE header. Given a virtual address to data in a mapped PE file, return the relative virtual address (displacement from start of the image) Given a relative virtual address (displacement from start of the image) return the virtual address to data in a mapped PE file Given a relative virtual address (displacement from start of the image) return a offset in the file data for that data. Returns true if this is PE file for a 64 bit architecture. Returns true if this file contains managed code (might also contain native code). Returns the 'Signature' of the PE HEader PE\0\0 = 0x4550, used for sanity checking. The machine this PE file is intended to run on PE files have a number of sections that represent regions of memory with the access permisions. This is the nubmer of such sections. The the PE file was created represented as the number of seconds since Jan 1 1970 The the PE file was created represented as a DateTime object PointerToSymbolTable (see IMAGE_FILE_HEADER in PE File spec) NumberOfSymbols (see IMAGE_FILE_HEADER PE File spec) SizeOfOptionalHeader (see IMAGE_FILE_HEADER PE File spec) Characteristics (see IMAGE_FILE_HEADER PE File spec) Magic (see IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64 in PE File spec) MajorLinkerVersion (see IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64 in PE File spec) MinorLinkerVersion (see IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64 in PE File spec) SizeOfCode (see IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64 in PE File spec) SizeOfInitializedData (see IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64 in PE File spec) SizeOfUninitializedData (see IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64 in PE File spec) AddressOfEntryPoint (see IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64 in PE File spec) BaseOfCode (see IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64 in PE File spec) ImageBase (see IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64 in PE File spec) SectionAlignment (see IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64 in PE File spec) FileAlignment (see IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64 in PE File spec) MajorOperatingSystemVersion (see IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64 in PE File spec) MinorOperatingSystemVersion (see IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64 in PE File spec) MajorImageVersion (see IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64 in PE File spec) MinorImageVersion (see IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64 in PE File spec) MajorSubsystemVersion (see IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64 in PE File spec) MinorSubsystemVersion (see IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64 in PE File spec) Win32VersionValue (see IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64 in PE File spec) SizeOfImage (see IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64 in PE File spec) SizeOfHeaders (see IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64 in PE File spec) CheckSum (see IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64 in PE File spec) Subsystem (see IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64 in PE File spec) DllCharacteristics (see IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64 in PE File spec) SizeOfStackReserve (see IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64 in PE File spec) SizeOfStackCommit (see IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64 in PE File spec) SizeOfHeapReserve (see IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64 in PE File spec) SizeOfHeapCommit (see IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64 in PE File spec) LoaderFlags (see IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64 in PE File spec) NumberOfRvaAndSizes (see IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64 in PE File spec) Returns the data directory (virtual address an blob, of a data directory with index 'idx'. 14 are currently defined. Returns the data directory for DLL Exports see PE file spec for more Returns the data directory for DLL Imports see PE file spec for more Returns the data directory for DLL Resources see PE file spec for more Returns the data directory for DLL Exceptions see PE file spec for more Returns the data directory for DLL securiy certificates (Authenticode) see PE file spec for more Returns the data directory Image Base Relocations (RELOCS) see PE file spec for more Returns the data directory for Debug information see PE file spec for more Returns the data directory for DLL Exports see PE file spec for more Returns the data directory for GlobalPointer (IA64) see PE file spec for more Returns the data directory for THread local storage see PE file spec for more Returns the data directory for Load Configuration see PE file spec for more Returns the data directory for Bound Imports see PE file spec for more Returns the data directory for the DLL Import Address Table (IAT) see PE file spec for more Returns the data directory for Delayed Imports see PE file spec for more see PE file spec for more .NET Runtime infomration. The Machine types supported by the portable executable (PE) File format Unknown machine type Intel X86 CPU Intel IA64 ARM 32 bit Arm 64 bit Represents a Portable Executable (PE) Data directory. This is just a well known optional 'Blob' of memory (has a starting point and size) The start of the data blob when the file is mapped into memory The length of the data blob. FileVersionInfo represents the extended version formation that is optionally placed in the PE file resource area. The version string A PEBuffer represents a buffer (efficient) scanner of the