private void RegisterListeners(TraceEventDispatcher source) { if ((_filter & EventFilter.Exception) == EventFilter.Exception) { // get exceptions source.Clr.ExceptionStart += OnExceptionStart; } if ((_filter & EventFilter.Finalizer) == EventFilter.Finalizer) { // get finalizers source.Clr.TypeBulkType += OnTypeBulkType; source.Clr.GCFinalizeObject += OnGCFinalizeObject; } if ((_filter & EventFilter.Contention) == EventFilter.Contention) { // get thread contention time source.Clr.ContentionStart += OnContentionStart; source.Clr.ContentionStop += OnContentionStop; } if ((_filter & EventFilter.ThreadStarvation) == EventFilter.ThreadStarvation) { // detect ThreadPool starvation source.Clr.ThreadPoolWorkerThreadAdjustmentAdjustment += OnThreadPoolWorkerAdjustment; } if ((_filter & EventFilter.GC) == EventFilter.GC) { source.NeedLoadedDotNetRuntimes(); source.AddCallbackOnProcessStart((TraceProcess proc) => { if (proc.ProcessID != _processId) { return; } proc.AddCallbackOnDotNetRuntimeLoad((TraceLoadedDotNetRuntime runtime) => { runtime.GCEnd += (TraceProcess p, TraceGC gc) => { NotifyCollection(gc); }; }); }); } if ((_filter & EventFilter.AllocationTick) == EventFilter.AllocationTick) { // sample every ~100 KB of allocations source.Clr.GCAllocationTick += OnGCAllocationTick; } }