public CallTreeDataProvider(TraceLog log, FilterParams filterParams, SymbolReader reader, ITraceDataPlugin plugin)
        {
            if (log == null)
            {
                ThrowHelper.ThrowArgumentNullException(nameof(log));
            }

            if (filterParams == null)
            {
                ThrowHelper.ThrowArgumentNullException(nameof(filterParams));
            }

            if (reader == null)
            {
                ThrowHelper.ThrowArgumentNullException(nameof(reader));
            }

            if (plugin == null)
            {
                ThrowHelper.ThrowArgumentNullException(nameof(plugin));
            }

            this.reader = reader;
            TraceEvents events = log.Events;
            var         unfilteredStacksource = plugin.GetStackSource(events);

            this.summaryPredicate       = plugin.SummaryPredicate;
            CallTree.DisableParallelism = true; // important
            this.stacksource            = new FilterStackSource(filterParams, unfilteredStacksource, ScalingPolicyKind.TimeMetric);
            this.callTree = new CallTree(ScalingPolicyKind.TimeMetric)
            {
                StackSource = this.stacksource
            };

            // Indicate I want the Time histograms to be computed.
            double startTimeRelativeMsec = 0;

            double.TryParse(filterParams.StartTimeRelativeMSec, out startTimeRelativeMsec);
            //System.Diagnostics.Debug.WriteLine("\n\nTIME: 1" + filterParams.StartTimeRelativeMSec + "\n2 " + startTimeRelativeMsec + "\n3 " + this.stacksource.SampleTimeRelativeMSecLimit + "\n\n");
            callTree.TimeHistogramController = new TimeHistogramController(callTree, startTimeRelativeMsec, this.stacksource.SampleTimeRelativeMSecLimit);
            float minIncusiveTimePercent;

            if (float.TryParse(filterParams.MinInclusiveTimePercent, out minIncusiveTimePercent) && minIncusiveTimePercent > 0)
            {
                this.callTree.FoldNodesUnder(minIncusiveTimePercent * this.callTree.Root.InclusiveMetric / 100, true);
            }
        }
        public CallTreeDataProvider(TraceLog log, FilterParams filterParams, SymbolReader reader, ITraceDataPlugin plugin)
        {
            if (log == null)
            {
                ThrowHelper.ThrowArgumentNullException(nameof(log));
            }

            if (filterParams == null)
            {
                ThrowHelper.ThrowArgumentNullException(nameof(filterParams));
            }

            if (reader == null)
            {
                ThrowHelper.ThrowArgumentNullException(nameof(reader));
            }

            if (plugin == null)
            {
                ThrowHelper.ThrowArgumentNullException(nameof(plugin));
            }

            this.reader = reader;
            TraceEvents events = log.Events;

            this.stacksource            = plugin.GetStackSource(events);
            this.summaryPredicate       = plugin.SummaryPredicate;
            CallTree.DisableParallelism = true; // important
            this.stacksource            = new FilterStackSource(filterParams, this.stacksource, ScalingPolicyKind.TimeMetric);

            this.callTree = new CallTree(ScalingPolicyKind.TimeMetric)
            {
                StackSource = this.stacksource
            };
            float minIncusiveTimePercent;

            if (float.TryParse(filterParams.MinInclusiveTimePercent, out minIncusiveTimePercent) && minIncusiveTimePercent > 0)
            {
                this.callTree.FoldNodesUnder(minIncusiveTimePercent * this.callTree.Root.InclusiveMetric / 100, true);
            }
        }