public override void Build(ITableBuilder tableBuilder)
        {
            if (PerfDataTxtLogParsed == null || PerfDataTxtLogParsed.Count == 0)
            {
                return;
            }

            var firstPerfDataTxtLogParsed = PerfDataTxtLogParsed.First().Value;  // First Log

            // Init
            IpStackFrames        = new ConcurrentDictionary <long, StackFrame>();
            SampleThreadDict     = new ConcurrentDictionary <long, int>();
            SampleProcessDict    = new ConcurrentDictionary <long, string>();
            SampleStackWalkEvent = new ConcurrentDictionary <long, ManualResetEvent>();

            var baseProjection = Projection.CreateUsingFuncAdaptor(new Func <int, LinuxPerfScriptStackSourceSample>(i => firstPerfDataTxtLogParsed.GetLinuxPerfScriptSampleByIndex((StackSourceSampleIndex)i)));

            // Calculate sample weights
            var sampleWeights = CalculateSampleWeights(firstPerfDataTxtLogParsed);

            var oneNs      = new TimestampDelta(1);
            var weightProj = baseProjection.Compose(s => s.SampleIndex == StackSourceSampleIndex.Invalid ? TimestampDelta.Zero : new TimestampDelta(Convert.ToInt64(sampleWeights[(int)s.SampleIndex] * 1000000)));

            // Constant columns
            var sampleIndex            = baseProjection.Compose(s => (long)s.SampleIndex);
            var timeStampProjection    = baseProjection.Compose(s => s.SampleIndex == StackSourceSampleIndex.Invalid ? Timestamp.Zero : new Timestamp(Convert.ToInt64(s.TimeRelativeMSec * 1000000)));
            var cpuProjection          = baseProjection.Compose(s => s.SampleIndex == StackSourceSampleIndex.Invalid ? -1 : s.CpuNumber);
            var countProjection        = baseProjection.Compose(s => 1);
            var ipStackFrameProjection = baseProjection.Compose(s => GetIpStackFrame(s, firstPerfDataTxtLogParsed)?.Frame);
            var ipModuleProjection     = baseProjection.Compose(s => GetIpStackFrame(s, firstPerfDataTxtLogParsed)?.Module);
            var threadIdProjection     = baseProjection.Compose(s => GetThreadId(s, firstPerfDataTxtLogParsed));
            var processProjection      = baseProjection.Compose(s => GetProcess(s, firstPerfDataTxtLogParsed));


            // For calculating cpu %
            var timeStampStartProjection = baseProjection.Compose(s => s.SampleIndex == StackSourceSampleIndex.Invalid ? Timestamp.Zero : new Timestamp(Convert.ToInt64(s.TimeRelativeMSec * 1000000)) - new TimestampDelta(Convert.ToInt64(sampleWeights[(int)s.SampleIndex] * 1000000)));
            IProjection <int, Timestamp> viewportClippedStartTimeProj = Projection.ClipTimeToVisibleDomain.Create(timeStampStartProjection);
            IProjection <int, Timestamp> viewportClippedEndTimeProj   = Projection.ClipTimeToVisibleDomain.Create(timeStampProjection);

            IProjection <int, TimestampDelta> clippedWeightProj = Projection.Select(
                viewportClippedEndTimeProj,
                viewportClippedStartTimeProj,
                new ReduceTimeSinceLastDiff());

            IProjection <int, double> weightPercentProj = Projection.VisibleDomainRelativePercent.Create(clippedWeightProj);

            IProjection <int, int> countProj = SequentialGenerator.Create(
                firstPerfDataTxtLogParsed.SampleIndexLimit,
                Projection.Constant(1),
                Projection.Constant(0));

            //
            // Table Configurations describe how your table should be presented to the user:
            // the columns to show, what order to show them, which columns to aggregate, and which columns to graph.
            // You may provide a number of columns in your table, but only want to show a subset of them by default so as not to overwhelm the user.
            // The user can still open the table properties to turn on or off columns.
            // The table configuration class also exposes four (4) columns UI explicitly recognizes: Pivot Column, Graph Column, Left Freeze Column, Right Freeze Column
            // For more information about what these columns do, go to "Advanced Topics" -> "Table Configuration" in our Wiki. Link can be found in README.md
            //

            const string filterIdleSamplesQuery = "[IP]:=\"native_safe_halt\"";

            var utilByCpuStackConfig = new TableConfiguration("Utilization by CPU, Stack")
            {
                Columns = new[]
                {
                    cpuColumn,
                    callStackColumn,
                    TableConfiguration.PivotColumn,
                    processColumn,
                    threadIdColumn,
                    instructionPointerColumn,
                    instructionPointerModuleColumn,
                    sampleNumberColumn,
                    timestampDateTimeColumn,
                    timestampColumn,
                    weightColumn,
                    countColumn,
                    TableConfiguration.GraphColumn,
                    weightPctColumn
                },
                InitialFilterShouldKeep = false,
                InitialFilterQuery      = filterIdleSamplesQuery,
            };

            utilByCpuStackConfig.AddColumnRole(ColumnRole.EndTime, timestampColumn);
            utilByCpuStackConfig.AddColumnRole(ColumnRole.Duration, weightColumn);
            utilByCpuStackConfig.AddColumnRole(ColumnRole.ResourceId, cpuColumn);

            var utilByCpuConfig = new TableConfiguration("Utilization by CPU")
            {
                Columns = new[]
                {
                    cpuColumn,
                    TableConfiguration.PivotColumn,
                    countColumn,
                    callStackColumn,
                    processColumn,
                    threadIdColumn,
                    instructionPointerColumn,
                    instructionPointerModuleColumn,
                    sampleNumberColumn,
                    timestampDateTimeColumn,
                    timestampColumn,
                    weightColumn,
                    TableConfiguration.GraphColumn,
                    weightPctColumn
                },
                InitialFilterShouldKeep = false,
                InitialFilterQuery      = filterIdleSamplesQuery,
            };

            utilByCpuConfig.AddColumnRole(ColumnRole.EndTime, timestampColumn);
            utilByCpuConfig.AddColumnRole(ColumnRole.Duration, weightColumn);
            utilByCpuConfig.AddColumnRole(ColumnRole.ResourceId, cpuColumn);

            var utilByProcessConfig = new TableConfiguration("Utilization by Process")
            {
                Columns = new[]
                {
                    processColumn,
                    TableConfiguration.PivotColumn,
                    countColumn,
                    callStackColumn,
                    cpuColumn,
                    threadIdColumn,
                    instructionPointerColumn,
                    instructionPointerModuleColumn,
                    sampleNumberColumn,
                    timestampDateTimeColumn,
                    timestampColumn,
                    weightColumn,
                    TableConfiguration.GraphColumn,
                    weightPctColumn
                },
                InitialFilterShouldKeep = false,
                InitialFilterQuery      = filterIdleSamplesQuery,
            };

            utilByProcessConfig.AddColumnRole(ColumnRole.EndTime, timestampColumn);
            utilByProcessConfig.AddColumnRole(ColumnRole.Duration, weightColumn);
            utilByProcessConfig.AddColumnRole(ColumnRole.ResourceId, cpuColumn);

            var utilByProcessStackConfig = new TableConfiguration("Utilization by Process, Stack")
            {
                Columns = new[]
                {
                    processColumn,
                    callStackColumn,
                    TableConfiguration.PivotColumn,
                    countColumn,
                    cpuColumn,
                    threadIdColumn,
                    instructionPointerColumn,
                    instructionPointerModuleColumn,
                    sampleNumberColumn,
                    timestampDateTimeColumn,
                    timestampColumn,
                    weightColumn,
                    TableConfiguration.GraphColumn,
                    weightPctColumn
                },
                InitialFilterShouldKeep = false,
                InitialFilterQuery      = filterIdleSamplesQuery,
            };

            utilByProcessStackConfig.AddColumnRole(ColumnRole.EndTime, timestampColumn);
            utilByProcessStackConfig.AddColumnRole(ColumnRole.Duration, weightColumn);
            utilByProcessStackConfig.AddColumnRole(ColumnRole.ResourceId, cpuColumn);

            var flameByProcessStackConfig = new TableConfiguration("Flame by Process, Stack")
            {
                Columns = new[]
                {
                    processColumn,
                    callStackColumn,
                    TableConfiguration.PivotColumn,
                    countColumn,
                    cpuColumn,
                    threadIdColumn,
                    instructionPointerColumn,
                    instructionPointerModuleColumn,
                    sampleNumberColumn,
                    timestampDateTimeColumn,
                    timestampColumn,
                    weightColumn,
                    TableConfiguration.GraphColumn,
                    weightPctColumn
                },
                ChartType = ChartType.Flame,
                InitialFilterShouldKeep = false,
                InitialFilterQuery      = filterIdleSamplesQuery,
            };

            flameByProcessStackConfig.AddColumnRole(ColumnRole.EndTime, timestampColumn);
            flameByProcessStackConfig.AddColumnRole(ColumnRole.Duration, weightColumn);
            flameByProcessStackConfig.AddColumnRole(ColumnRole.ResourceId, cpuColumn);

            //
            //
            //  Use the table builder to build the table.
            //  Add and set table configuration if applicable.
            //  Then set the row count (we have one row per file) and then add the columns using AddColumn.
            //
            var table = tableBuilder
                        .AddTableConfiguration(utilByCpuStackConfig)
                        .SetDefaultTableConfiguration(utilByCpuStackConfig)
                        .AddTableConfiguration(utilByCpuConfig)
                        .AddTableConfiguration(utilByProcessConfig)
                        .AddTableConfiguration(utilByProcessStackConfig)
                        .AddTableConfiguration(flameByProcessStackConfig)
                        .SetRowCount(firstPerfDataTxtLogParsed.SampleIndexLimit)
                        .AddColumn(sampleNumberColumn, sampleIndex)
                        .AddColumn(timestampColumn, timeStampProjection)
                        .AddColumn(instructionPointerColumn, ipStackFrameProjection)
                        .AddColumn(instructionPointerModuleColumn, ipModuleProjection)
                        .AddColumn(countColumn, countProjection)
                        .AddColumn(weightColumn, weightProj)
                        .AddColumn(threadIdColumn, threadIdProjection)
                        .AddColumn(processColumn, processProjection)
                        .AddColumn(weightPctColumn, weightPercentProj)
                        .AddColumn(startTimeCol, timeStampStartProjection)
                        .AddColumn(viewportClippedStartTimeCol, viewportClippedStartTimeProj)
                        .AddColumn(viewportClippedEndTimeCol, viewportClippedEndTimeProj)
                        .AddColumn(clippedWeightCol, clippedWeightProj)
                        .AddColumn(cpuColumn, cpuProjection)
            ;

            table.AddHierarchicalColumn(callStackColumn, baseProjection.Compose((i) => GetCallStack(i, firstPerfDataTxtLogParsed)), new ArrayAccessProvider <string>());
        }
        public static void BuildTable(ITableBuilder tableBuilder, IDataExtensionRetrieval tableData)
        {
            var pathIdentifier = DataOutputPath.ForSource(PerfConstants.SourceId, PerfCpuClockDataCooker.Identifier, nameof(PerfCpuClockDataCooker.CpuClockEvents));

            var cpuClocks = tableData.QueryOutput <IReadOnlyList <ICpuClockEvent> >(pathIdentifier);

            if (cpuClocks.Count == 0)
            {
                return;
            }

            var config = new TableConfiguration("CPU Utilization")
            {
                Columns = new[]
                {
                    cpuColumn,
                    callStackColumn,
                    TableConfiguration.PivotColumn,
                    pidColumn,
                    threadIdColumn,
                    ipColumn,
                    symbolTypeColumn,
                    ipSymbolColumn,
                    idColumn,
                    weightColumn,
                    countColumn,
                    timeStampColumn,
                    TableConfiguration.GraphColumn,
                    weightPctColumn
                },
            };

            config.AddColumnRole(ColumnRole.EndTime, timeStampColumn);
            config.AddColumnRole(ColumnRole.Duration, weightColumn);
            config.AddColumnRole(ColumnRole.ResourceId, cpuColumn);

            var table = tableBuilder.AddTableConfiguration(config)
                        .SetDefaultTableConfiguration(config)
                        .SetRowCount(cpuClocks.Count);

            var timeStampProjection = Projection.CreateUsingFuncAdaptor((i) => cpuClocks[i].Timestamp);

            table.AddColumn(cpuColumn, Projection.CreateUsingFuncAdaptor((i) => cpuClocks[i].Cpu));
            table.AddColumn(ipColumn, Projection.CreateUsingFuncAdaptor((i) => cpuClocks[i].Ip));
            table.AddColumn(symbolTypeColumn, Projection.CreateUsingFuncAdaptor((i) => cpuClocks[i].Ip_Symbol?.SymbolType?.SymbolTypeDescription.SymbolTypeShortName));
            table.AddColumn(ipSymbolColumn, Projection.CreateUsingFuncAdaptor((i) => cpuClocks[i].Ip_Symbol?.Name));
            table.AddColumn(threadIdColumn, Projection.CreateUsingFuncAdaptor((i) => cpuClocks[i].Tid));
            table.AddColumn(pidColumn, Projection.CreateUsingFuncAdaptor((i) => cpuClocks[i].Pid));
            table.AddColumn(idColumn, Projection.CreateUsingFuncAdaptor((i) => cpuClocks[i].Id));
            table.AddColumn(perfPeriodColumn, Projection.CreateUsingFuncAdaptor((i) => cpuClocks[i].Perf_Period));
            table.AddColumn(perfCallchainSizeColumn, Projection.CreateUsingFuncAdaptor((i) => cpuClocks[i].Perf_Callchain_Size));
            table.AddHierarchicalColumn(callStackColumn, Projection.CreateUsingFuncAdaptor((i) => cpuClocks[i].CallStack), new ArrayAccessProvider <string>());
            table.AddColumn(timeStampColumn, timeStampProjection);

            var oneMsSample = new TimestampDelta(1000000); // 1ms for now until we can figure out weight better
            var oneNs       = new TimestampDelta(1);
            var weightProj  = Projection.Constant(oneMsSample);

            var timeStampStartProjection = Projection.CreateUsingFuncAdaptor((i) => cpuClocks[i].Timestamp - oneNs); // We will say sample lasted 1ns
            IProjection <int, Timestamp> viewportClippedStartTimeProj = Projection.ClipTimeToVisibleDomain.Create(timeStampStartProjection);
            IProjection <int, Timestamp> viewportClippedEndTimeProj   = Projection.ClipTimeToVisibleDomain.Create(timeStampProjection);

            IProjection <int, TimestampDelta> clippedWeightProj = Projection.Select(
                viewportClippedEndTimeProj,
                viewportClippedStartTimeProj,
                new ReduceTimeSinceLastDiff());

            IProjection <int, double> weightPercentProj = Projection.VisibleDomainRelativePercent.Create(clippedWeightProj);

            IProjection <int, int> countProj = SequentialGenerator.Create(
                cpuClocks.Count,
                Projection.Constant(1),
                Projection.Constant(0));

            table.AddColumn(weightColumn, weightProj);
            table.AddColumn(countColumn, countProj);
            table.AddColumn(weightPctColumn, weightPercentProj);
            table.AddColumn(startTimeCol, timeStampStartProjection);
            table.AddColumn(viewportClippedStartTimeCol, viewportClippedStartTimeProj);
            table.AddColumn(viewportClippedEndTimeCol, viewportClippedEndTimeProj);
            table.AddColumn(clippedWeightCol, clippedWeightProj);
        }