public void Project_3_ThrowsForNull() { Assert.ThrowsException <ArgumentNullException>( () => Projection.Project <int, DateTime, Guid, TimeSpan, string>( null, Projection.Constant(Guid.NewGuid()), Projection.Constant(TimeSpan.Zero), Project_3_Projector)); Assert.ThrowsException <ArgumentNullException>( () => Projection.Project <int, DateTime, Guid, TimeSpan, string>( Projection.Constant(DateTime.UtcNow), null, Projection.Constant(TimeSpan.Zero), Project_3_Projector)); Assert.ThrowsException <ArgumentNullException>( () => Projection.Project <int, DateTime, Guid, TimeSpan, string>( Projection.Constant(DateTime.UtcNow), Projection.Constant(Guid.NewGuid()), null, Project_3_Projector)); Assert.ThrowsException <ArgumentNullException>( () => Projection.Project <int, DateTime, Guid, TimeSpan, string>( Projection.Constant(DateTime.UtcNow), Projection.Constant(Guid.NewGuid()), Projection.Constant(TimeSpan.Zero), null)); }
public void Project_1_ThrowsIfNonStaticFuncGiven() { Assert.ThrowsException <InvalidOperationException>( () => Projection.Project <int, DateTime, string>( Projection.Constant(DateTime.UtcNow), x => x.ToString())); }
public void IsConstant_ReturnsTrueForConstantProject() { var projection = Projection.Constant(1); Assert.IsTrue(Projection.IsConstant(projection)); Assert.IsTrue(projection.IsConstant()); }
public static void BuildTable(ITableBuilder tableBuilder, IDataExtensionRetrieval tableData) { Debug.Assert(!(tableBuilder is null) && !(tableData is null)); var quicState = tableData.QueryOutput <QuicState>(new DataOutputPath(QuicEventCooker.CookerPath, "State")); if (quicState == null) { return; } var events = quicState.Events .Where(x => x.ID == QuicEventId.StreamCreated || x.ID == QuicEventId.StreamDestroyed).ToArray(); if (events.Length == 0) { return; } var table = tableBuilder.SetRowCount(events.Length); var dataProjection = Projection.Index(events); table.AddColumn(typeColumnConfig, dataProjection.Compose(ProjectType)); table.AddColumn(countColumnConfig, Projection.Constant <uint>(1)); table.AddColumn(timeColumnConfig, dataProjection.Compose(ProjectTime)); tableConfig1.AddColumnRole(ColumnRole.StartTime, timeColumnConfig); tableBuilder.AddTableConfiguration(tableConfig1); tableBuilder.SetDefaultTableConfiguration(tableConfig1); }
public void ConstantTitleProjection_NameIsConstantReturnsTrue() { var projection = Projection.Constant("name"); var metadata = new ColumnMetadata(this.ColumnGuid, "default", projection, "test column"); Assert.IsTrue(metadata.IsNameConstant); }
public void Project_2_ThrowsIfNonStaticFuncGiven() { Assert.ThrowsException <InvalidOperationException>( () => Projection.Project <int, DateTime, Guid, string>( Projection.Constant(DateTime.UtcNow), Projection.Constant(Guid.NewGuid()), (x, y) => (x.ToString() + y.ToString()))); }
public static void BuildTable(ITableBuilder tableBuilder, IDataExtensionRetrieval tableData) { Debug.Assert(!(tableBuilder is null) && !(tableData is null)); var quicState = tableData.QueryOutput <QuicState>(new DataOutputPath(QuicEventCooker.CookerPath, "State")); if (quicState == null) { return; } var connections = quicState.Connections; if (connections.Count == 0) { return; } var connData = connections.SelectMany( x => x.GetFlowBlockedEvents() .Where(x => x.Flags != QuicFlowBlockedFlags.None) .Select(y => new Data(x, y))); var streamData = connections.SelectMany( x => x.Streams.SelectMany( y => y.GetFlowBlockedEvents() .Where(z => z.Flags != QuicFlowBlockedFlags.None) .Select(z => new Data(x, z, y)))); var data = connData.Concat(streamData).ToArray(); var table = tableBuilder.SetRowCount(data.Length); var dataProjection = Projection.Index(data); table.AddColumn(connectionColumnConfig, dataProjection.Compose(ProjectId)); table.AddColumn(streamColumnConfig, dataProjection.Compose(ProjectStreamId)); table.AddColumn(processIdColumnConfig, dataProjection.Compose(ProjectProcessId)); table.AddColumn(reasonColumnConfig, dataProjection.Compose(ProjectReason)); table.AddColumn(countColumnConfig, Projection.Constant <uint>(1)); table.AddColumn(weightColumnConfig, dataProjection.Compose(ProjectWeight)); table.AddColumn(percentWeightColumnConfig, dataProjection.Compose(ProjectPercentWeight)); table.AddColumn(timeColumnConfig, dataProjection.Compose(ProjectTime)); table.AddColumn(durationColumnConfig, dataProjection.Compose(ProjectDuration)); tableConfig1.AddColumnRole(ColumnRole.StartTime, timeColumnConfig); tableConfig1.AddColumnRole(ColumnRole.Duration, durationColumnConfig); tableConfig1.InitialSelectionQuery = "[Series Name]:=\"Connection\" OR [Series Name]:=\"Reason\""; tableBuilder.AddTableConfiguration(tableConfig1); tableConfig2.AddColumnRole(ColumnRole.StartTime, timeColumnConfig); tableConfig2.AddColumnRole(ColumnRole.Duration, durationColumnConfig); tableConfig2.InitialSelectionQuery = "[Series Name]:=\"Reason\""; tableBuilder.AddTableConfiguration(tableConfig2); tableBuilder.SetDefaultTableConfiguration(tableConfig1); }
public void Project_4_ThrowsIfNonStaticFuncGiven() { Assert.ThrowsException <InvalidOperationException>( () => Projection.Project <int, DateTime, Guid, TimeSpan, DateTimeOffset, string>( Projection.Constant(DateTime.UtcNow), Projection.Constant(Guid.NewGuid()), Projection.Constant(TimeSpan.Zero), Projection.Constant(DateTimeOffset.MaxValue), (x, y, z, a) => (x.ToString() + y.ToString() + z.ToString() + a.ToString()))); }
public void ConstantTitleProjection_NameStillRespectsDefault() { var projection = Projection.Constant("name"); var metadata = new ColumnMetadata(this.ColumnGuid, "default", projection, "test column"); for (var i = 0; i < 1000; ++i) { Assert.AreEqual("default", metadata.Name); } }
public void ConstantProjectionAlwaysReturnsTheSameValue() { var value = Guid.NewGuid(); var projection = Projection.Constant(value); for (var i = 0; i < 100; ++i) { Assert.AreEqual(value, projection[i]); } }
public void Project_1_ThrowsForNull() { Assert.ThrowsException <ArgumentNullException>( () => Projection.Project <int, DateTime, string>( null, Project_1_Projector)); Assert.ThrowsException <ArgumentNullException>( () => Projection.Project <int, DateTime, string>( Projection.Constant(DateTime.UtcNow), null)); }
public static void BuildTable(ITableBuilder tableBuilder, IDataExtensionRetrieval tableData) { Debug.Assert(!(tableBuilder is null) && !(tableData is null)); var quicState = tableData.QueryOutput <QuicState>(new DataOutputPath(QuicEventCooker.CookerPath, "State")); if (quicState == null) { return; } var connections = quicState.Connections; if (connections.Count == 0) { return; } var data = connections.SelectMany( x => x.GetExecutionEvents().Select( y => new ValueTuple <QuicConnection, QuicExecutionData>(x, y))).ToArray(); var table = tableBuilder.SetRowCount(data.Length); var dataProjection = Projection.Index(data); table.AddColumn(connectionColumnConfig, dataProjection.Compose(ProjectId)); table.AddColumn(processIdColumnConfig, dataProjection.Compose(ProjectProcessId)); table.AddColumn(threadIdColumnConfig, dataProjection.Compose(ProjectThreadId)); table.AddColumn(cpuColumnConfig, dataProjection.Compose(ProjectCpu)); table.AddColumn(nameColumnConfig, dataProjection.Compose(ProjectName)); table.AddColumn(countColumnConfig, Projection.Constant <uint>(1)); table.AddColumn(weightColumnConfig, dataProjection.Compose(ProjectWeight)); table.AddColumn(percentWeightColumnConfig, dataProjection.Compose(ProjectPercentWeight)); table.AddColumn(timeColumnConfig, dataProjection.Compose(ProjectTime)); table.AddColumn(durationColumnConfig, dataProjection.Compose(ProjectDuration)); tableConfig1.AddColumnRole(ColumnRole.StartTime, timeColumnConfig); tableConfig1.AddColumnRole(ColumnRole.Duration, durationColumnConfig); //tableConfig1.InitialExpansionQuery = "[Series Name]:=\"Process (ID)\""; //tableConfig1.InitialSelectionQuery = "[Series Name]:=\"Connection\" OR [Series Name]:=\"State\""; tableBuilder.AddTableConfiguration(tableConfig1); tableConfig2.AddColumnRole(ColumnRole.StartTime, timeColumnConfig); tableConfig2.AddColumnRole(ColumnRole.Duration, durationColumnConfig); tableConfig2.AddColumnRole(ColumnRole.ResourceId, cpuColumnConfig); //tableConfig2.InitialExpansionQuery = "[Series Name]:=\"Process (ID)\""; //tableConfig2.InitialSelectionQuery = "[Series Name]:=\"State\""; tableBuilder.AddTableConfiguration(tableConfig2); tableBuilder.SetDefaultTableConfiguration(tableConfig1); }
public static void BuildTable(ITableBuilder tableBuilder, IDataExtensionRetrieval tableData) { Debug.Assert(!(tableBuilder is null) && !(tableData is null)); var quicState = tableData.QueryOutput <QuicState>(new DataOutputPath(QuicEventCooker.CookerPath, "State")); if (quicState == null) { return; } var data = quicState.GetApiCalls(); if (data.Count == 0) { return; } var table = tableBuilder.SetRowCount(data.Count); var dataProjection = Projection.Index(data); table.AddColumn(typeColumnConfig, dataProjection.Compose(ProjectType)); table.AddColumn(processIdColumnConfig, dataProjection.Compose(ProjectProcessId)); table.AddColumn(threadIdColumnConfig, dataProjection.Compose(ProjectThreadId)); table.AddColumn(cpuColumnConfig, dataProjection.Compose(ProjectCpu)); table.AddColumn(pointerColumnConfig, dataProjection.Compose(ProjectPointer)); table.AddColumn(resultColumnConfig, dataProjection.Compose(ProjectResult)); table.AddColumn(countColumnConfig, Projection.Constant <uint>(1)); table.AddColumn(timeColumnConfig, dataProjection.Compose(ProjectTime)); table.AddColumn(durationColumnConfig, dataProjection.Compose(ProjectDuration)); tableConfig1.AddColumnRole(ColumnRole.StartTime, timeColumnConfig); tableConfig1.AddColumnRole(ColumnRole.Duration, durationColumnConfig); tableBuilder.AddTableConfiguration(tableConfig1); tableConfig2.AddColumnRole(ColumnRole.StartTime, timeColumnConfig); tableConfig2.AddColumnRole(ColumnRole.Duration, durationColumnConfig); tableBuilder.AddTableConfiguration(tableConfig2); tableBuilder.SetDefaultTableConfiguration(tableConfig1); }
/// <summary> /// Initializes a new instance of the <see cref="ColumnMetadata"/> /// class. /// </summary> /// <param name="guid"> /// The unique identifier for this column. This MAY NOT be /// the default (empty) <see cref="Guid"/>. /// </param> /// <param name="name"> /// The name of this column. /// </param> /// <param name="description"> /// A user friendly description of this column. /// </param> /// <exception cref="System.ArgumentException"> /// <paramref name="guid"/> is equal to <c>default(Guid)</c>. /// - or - /// <paramref name="name"/> is whitespace. /// - or - /// <paramref name="description"/> is whitespace. /// </exception> /// <exception cref="System.ArgumentNullException"> /// <paramref name="name"/> is <c>null</c>. /// - or - /// <paramref name="description"/> is <c>null</c>. /// </exception> public ColumnMetadata(Guid guid, string name, string description) : this(guid, name, Projection.Constant(name), description) { }
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); }
public static void BuildTable(ITableBuilder tableBuilder, IDataExtensionRetrieval tableData) { // We dynamically adjust the column headers // This is the max number of fields we can expect for this table int maxFieldCount = Math.Min(AbsoluteMaxFields, tableData.QueryOutput <int>( new DataOutputPath(PerfettoPluginConstants.GenericEventCookerPath, nameof(PerfettoGenericEventCooker.MaximumEventFieldCount)))); bool hasProviders = tableData.QueryOutput <bool>( new DataOutputPath(PerfettoPluginConstants.GenericEventCookerPath, nameof(PerfettoGenericEventCooker.HasProviders))); // Get data from the cooker var events = tableData.QueryOutput <ProcessedEventData <PerfettoGenericEvent> >( new DataOutputPath(PerfettoPluginConstants.GenericEventCookerPath, nameof(PerfettoGenericEventCooker.GenericEvents))); var tableGenerator = tableBuilder.SetRowCount((int)events.Count); var genericEventProjection = new EventProjection <PerfettoGenericEvent>(events); // Add all the data projections var sliceIdColumn = new DataColumn <int>( SliceIdColConfig, genericEventProjection.Compose((genericEvent) => genericEvent.SliceId)); tableGenerator.AddColumn(sliceIdColumn); var processNameColumn = new DataColumn <string>( ProcessNameColConfig, genericEventProjection.Compose((genericEvent) => genericEvent.Process)); tableGenerator.AddColumn(processNameColumn); var processLabelColumn = new DataColumn <string>( ProcessLabelColConfig, genericEventProjection.Compose((genericEvent) => genericEvent.ProcessLabel)); tableGenerator.AddColumn(processLabelColumn); if (events.Any(f => !String.IsNullOrWhiteSpace(f.ProcessLabel))) { ProcessLabelColConfig.DisplayHints.IsVisible = true; } var threadNameColumn = new DataColumn <string>( ThreadNameColConfig, genericEventProjection.Compose((genericEvent) => genericEvent.Thread)); tableGenerator.AddColumn(threadNameColumn); var eventNameColumn = new DataColumn <string>( EventNameColConfig, genericEventProjection.Compose((genericEvent) => genericEvent.EventName)); tableGenerator.AddColumn(eventNameColumn); var startTimestampColumn = new DataColumn <Timestamp>( StartTimestampColConfig, genericEventProjection.Compose((genericEvent) => genericEvent.StartTimestamp)); tableGenerator.AddColumn(startTimestampColumn); var endTimestampColumn = new DataColumn <Timestamp>( EndTimestampColConfig, genericEventProjection.Compose((genericEvent) => genericEvent.EndTimestamp)); tableGenerator.AddColumn(endTimestampColumn); var durationColumn = new DataColumn <TimestampDelta>( DurationNotSortedColConfig, genericEventProjection.Compose((genericEvent) => genericEvent.Duration)); tableGenerator.AddColumn(durationColumn); var durationExColumn = new DataColumn <TimestampDelta>( DurationExSortedColConfig, genericEventProjection.Compose((genericEvent) => genericEvent.DurationExclusive)); tableGenerator.AddColumn(durationExColumn); var categoryColumn = new DataColumn <string>( CategoryColConfig, genericEventProjection.Compose((genericEvent) => genericEvent.Category)); tableGenerator.AddColumn(categoryColumn); var typeColumn = new DataColumn <string>( TypeColConfig, genericEventProjection.Compose((genericEvent) => genericEvent.Type)); tableGenerator.AddColumn(typeColumn); var providerColumn = new DataColumn <string>( ProviderColConfig, genericEventProjection.Compose((genericEvent) => genericEvent.Provider)); tableGenerator.AddColumn(providerColumn); var trackNameIdColumn = new DataColumn <string>( TrackNameIdColConfig, genericEventProjection.Compose((genericEvent) => genericEvent.ThreadTrack != null ? (!String.IsNullOrWhiteSpace(genericEvent.ThreadTrack.Name) ? $"{genericEvent.ThreadTrack.Name} ({genericEvent.ThreadTrack.Id})" : genericEvent.ThreadTrack.Id.ToString()) : String.Empty)); tableGenerator.AddColumn(trackNameIdColumn); var parentIdColumn = new DataColumn <int>( ParentIdColConfig, genericEventProjection.Compose((genericEvent) => genericEvent.ParentId.HasValue ? genericEvent.ParentId.Value : -1)); tableGenerator.AddColumn(parentIdColumn); var parentDepthLevelColumn = new DataColumn <int>( ParentDepthLevelColConfig, genericEventProjection.Compose((genericEvent) => genericEvent.ParentTreeDepthLevel)); tableGenerator.AddColumn(parentDepthLevelColumn); tableGenerator.AddHierarchicalColumn(ParentEventNameTreeBranchColConfig, genericEventProjection.Compose((genericEvent) => genericEvent.ParentEventNameTree), new ArrayAccessProvider <string>()); tableGenerator.AddColumn(CountColConfig, Projection.Constant <int>(1)); // The provider column is optionally populated depending on whether or not the user specified a ProviderGUID mapping file ProviderColConfig.DisplayHints.IsVisible = hasProviders; List <ColumnConfiguration> fieldColumns = new List <ColumnConfiguration>(); // Add the field columns, with column names depending on the given event for (int index = 0; index < maxFieldCount; index++) { var colIndex = index; // This seems unncessary but causes odd runtime behavior if not done this way. Compiler is confused perhaps because w/o this func will index=genericEvent.FieldNames.Count every time. index is passed as ref but colIndex as value into func string fieldName = "Field " + (colIndex + 1); var genericEventFieldNameProjection = genericEventProjection.Compose((genericEvent) => colIndex < genericEvent.Args?.Count ? genericEvent.Args.ElementAt(colIndex).Key : string.Empty); // generate a column configuration var fieldColumnConfiguration = new ColumnConfiguration( new ColumnMetadata(Common.GenerateGuidFromName(fieldName), fieldName, genericEventFieldNameProjection, fieldName) { IsDynamic = true }, new UIHints { IsVisible = true, Width = 150, TextAlignment = TextAlignment.Left, }); // Add this column to the column order fieldColumns.Add(fieldColumnConfiguration); var genericEventFieldAsStringProjection = genericEventProjection.Compose((genericEvent) => colIndex < genericEvent.Args?.Count ? genericEvent.Args.ElementAt(colIndex).Value : string.Empty); tableGenerator.AddColumn(fieldColumnConfiguration, genericEventFieldAsStringProjection); } List <ColumnConfiguration> defaultColumns = new List <ColumnConfiguration>() { ProviderColConfig, ProcessNameColConfig, ProcessLabelColConfig, ThreadNameColConfig, TableConfiguration.PivotColumn, // Columns before this get pivotted on EventNameColConfig, CategoryColConfig, TypeColConfig, DurationNotSortedColConfig, DurationExSortedColConfig, }; defaultColumns.AddRange(fieldColumns); defaultColumns.Add(TableConfiguration.GraphColumn); // Columns after this get graphed defaultColumns.Add(StartTimestampColConfig); defaultColumns.Add(EndTimestampColConfig); // Proces-Thread config var processThreadConfig = new TableConfiguration("Process-Thread") { Columns = defaultColumns, }; SetGraphTableConfig(processThreadConfig); tableBuilder.AddTableConfiguration(processThreadConfig); // Process-Thread by StartTime config var processThreadByStartTimeColumns = new List <ColumnConfiguration>(defaultColumns); processThreadByStartTimeColumns.Remove(EndTimestampColConfig); processThreadByStartTimeColumns.Insert(processThreadByStartTimeColumns.Count - 2, EndTimestampColConfig); var processThreadByStartTimeConfig = new TableConfiguration("Process-Thread by Start Time") { Columns = processThreadByStartTimeColumns, }; SetGraphTableConfig(processThreadByStartTimeConfig); tableBuilder.AddTableConfiguration(processThreadByStartTimeConfig); // Process-Thread Activity config var processThreadActivityColumns = new List <ColumnConfiguration>(defaultColumns); processThreadActivityColumns.Remove(StartTimestampColConfig); processThreadActivityColumns.Insert(10, StartTimestampColConfig); processThreadActivityColumns.Remove(EndTimestampColConfig); processThreadActivityColumns.Insert(11, EndTimestampColConfig); processThreadActivityColumns.Add(CountSortedColConfig); // Different sorting than default processThreadActivityColumns.Remove(DurationExSortedColConfig); processThreadActivityColumns.Insert(9, DurationExNotSortedMaxColConfig); DurationExNotSortedMaxColConfig.DisplayHints.SortPriority = 1; DurationExNotSortedMaxColConfig.DisplayHints.SortOrder = SortOrder.Descending; var processThreadActivityConfig = new TableConfiguration("Process-Thread Activity") { Columns = processThreadActivityColumns, }; SetGraphTableConfig(processThreadActivityConfig); tableBuilder.AddTableConfiguration(processThreadActivityConfig); // Default - Process-Thread-NestedSlices-Name config var processThreadNameColumns = new List <ColumnConfiguration>(defaultColumns); processThreadNameColumns.Insert(4, ParentDepthLevelColConfig); processThreadNameColumns.Remove(EventNameColConfig); processThreadNameColumns.Insert(5, EventNameColConfig); var processThreadNestedNameConfig = new TableConfiguration("Process-Thread-NestedSlices-Name") { Columns = processThreadNameColumns, }; SetGraphTableConfig(processThreadNestedNameConfig); tableBuilder.AddTableConfiguration(processThreadNestedNameConfig) .SetDefaultTableConfiguration(processThreadNestedNameConfig); // Process-Thread-EventName config var processThreadEventNameColumns = new List <ColumnConfiguration>(defaultColumns); processThreadEventNameColumns.Remove(EventNameColConfig); processThreadEventNameColumns.Insert(4, EventNameColConfig); var processThreadEventNameConfig = new TableConfiguration("Process-Thread-Name") { Columns = processThreadEventNameColumns, }; SetGraphTableConfig(processThreadEventNameConfig); tableBuilder.AddTableConfiguration(processThreadEventNameConfig); // Process-Thread-Name by StartTime config var processThreadNameByStartTimeColumns = new List <ColumnConfiguration>(defaultColumns); processThreadNameByStartTimeColumns.Insert(4, ParentDepthLevelColConfig); processThreadNameByStartTimeColumns.Remove(EventNameColConfig); processThreadNameByStartTimeColumns.Insert(5, EventNameColConfig); processThreadNameByStartTimeColumns.Remove(EndTimestampColConfig); processThreadNameByStartTimeColumns.Insert(processThreadNameByStartTimeColumns.Count - 2, EndTimestampColConfig); var processThreadNameByStartTimeConfig = new TableConfiguration("Process-Thread-Name by Start Time") { Columns = processThreadNameByStartTimeColumns, }; SetGraphTableConfig(processThreadNameByStartTimeConfig); tableBuilder.AddTableConfiguration(processThreadNameByStartTimeConfig); // Process-Thread-ParentTree config var processThreadNameTreeColumns = new List <ColumnConfiguration>(defaultColumns); processThreadNameTreeColumns.Insert(4, ParentEventNameTreeBranchColConfig); processThreadNameTreeColumns.Remove(DurationExSortedColConfig); processThreadNameTreeColumns.Insert(10, DurationExSortedSumColConfig); var processThreadParentNameTreeConfig = new TableConfiguration("Process-Thread-ParentTree") { Columns = processThreadNameTreeColumns, }; ParentEventNameTreeBranchColConfig.DisplayHints.IsVisible = true; SetGraphTableConfig(processThreadParentNameTreeConfig); tableBuilder.AddTableConfiguration(processThreadParentNameTreeConfig); }
public static void BuildTable(ITableBuilder tableBuilder, IDataExtensionRetrieval tableData) { int maximumFieldCount = tableData.QueryOutput <int>( DataOutputPath.ForSource(LTTngConstants.SourceId, LTTngGenericEventDataCooker.Identifier, nameof(LTTngGenericEventDataCooker.MaximumEventFieldCount))); var events = tableData.QueryOutput <ProcessedEventData <LTTngGenericEvent> >( DataOutputPath.ForSource(LTTngConstants.SourceId, LTTngGenericEventDataCooker.Identifier, nameof(LTTngGenericEventDataCooker.Events))); var tableGenerator = tableBuilder.SetRowCount((int)events.Count); var genericEventProjection = new EventProjection <LTTngGenericEvent>(events); var eventNameColumn = new DataColumn <string>( eventNameColumnConfig, genericEventProjection.Compose((genericEvent) => genericEvent.EventName)); tableGenerator.AddColumn(eventNameColumn); var eventIdColumn = new DataColumn <uint>( eventIdColumnConfig, genericEventProjection.Compose((genericEvent) => genericEvent.Id)); tableGenerator.AddColumn(eventIdColumn); var cpuIdColumn = new DataColumn <uint>( cpuIdColumnConfig, genericEventProjection.Compose((genericEvent) => genericEvent.CpuId)); tableGenerator.AddColumn(cpuIdColumn); var discardedEventsColumn = new DataColumn <uint>( discardedEventsColumnConfig, genericEventProjection.Compose((genericEvent) => genericEvent.DiscardedEvents)); tableGenerator.AddColumn(discardedEventsColumn); var eventTimestampColumn = new DataColumn <Timestamp>( eventTimestampColumnConfig, genericEventProjection.Compose((genericEvent) => genericEvent.Timestamp)); tableGenerator.AddColumn(eventTimestampColumn); tableGenerator.AddColumn(countColumnConfig, Projection.Constant(1)); // Add the field columns, with column names depending on the given event for (int index = 0; index < maximumFieldCount; index++) { var colIndex = index; // This seems unncessary but causes odd runtime behavior if not done this way. Compiler is confused perhaps because w/o this func will index=genericEvent.FieldNames.Count every time. index is passed as ref but colIndex as value into func string fieldName = "Field " + (colIndex + 1); var genericEventFieldNameProjection = genericEventProjection.Compose((genericEvent) => colIndex < genericEvent.FieldNames.Count ? genericEvent.FieldNames[colIndex] : string.Empty); // generate a column configuration var fieldColumnConfiguration = new ColumnConfiguration( new ColumnMetadata(Common.GenerateGuidFromName(fieldName), fieldName, genericEventFieldNameProjection, fieldName), new UIHints { IsVisible = true, Width = 80, TextAlignment = TextAlignment.Left, }); var genericEventFieldAsStringProjection = genericEventProjection.Compose((genericEvent) => colIndex < genericEvent.FieldNames.Count ? genericEvent.FieldValues[colIndex] : string.Empty); tableGenerator.AddColumn(fieldColumnConfiguration, genericEventFieldAsStringProjection); } }
public static void BuildTable(ITableBuilder tableBuilder, IDataExtensionRetrieval tableData) { var diskEvents = tableData.QueryOutput <IReadOnlyList <IDiskActivity> >( DataOutputPath.Create(LTTngDiskDataCooker.CookerPath + '/' + nameof(LTTngDiskDataCooker.DiskActivity))); if (diskEvents.Count == 0) { return; } var iosByDeviceThCmdConfig = new TableConfiguration("IOs by Device, ThreadId, Command") { Columns = new[] { deviceIdColumn, deviceNameColumn, threadIdColumn, commandColumn, TableConfiguration.PivotColumn, processIdColumn, filepathColumn, ioTimeSumColumn, sectorNumberColumn, diskOffsetColumn, sizeColumn, errorColumn, TableConfiguration.GraphColumn, insertTimeColumn, issueTimeColumn, completeTimeColumn }, Layout = TableLayoutStyle.GraphAndTable, }; var ioTimesByDevFileConfig = new TableConfiguration("IOTime by Device, FilePath") { Columns = new[] { deviceIdColumn, deviceNameColumn, TableConfiguration.PivotColumn, filepathColumn, threadIdColumn, processIdColumn, commandColumn, sectorNumberColumn, diskOffsetColumn, sizeColumn, errorColumn, insertTimeColumn, issueTimeColumn, completeTimeColumn, TableConfiguration.GraphColumn, ioTimeAvgColumn, ioTimeMaxColumn }, Layout = TableLayoutStyle.GraphAndTable, }; iosByDeviceThCmdConfig.AddColumnRole(ColumnRole.StartTime, insertTimeColumn); // config.AddColumnRole(ColumnRole.EndTime, completeTimeColumn); iosByDeviceThCmdConfig.AddColumnRole(ColumnRole.ResourceId, deviceIdColumn); // We have had past behavior where specifying this causes DevId 0 not to show? var table = tableBuilder.AddTableConfiguration(iosByDeviceThCmdConfig) .AddTableConfiguration(ioTimesByDevFileConfig) .SetDefaultTableConfiguration(iosByDeviceThCmdConfig) .SetRowCount((int)diskEvents.Count); var diskActivities = Projection.CreateUsingFuncAdaptor((i) => diskEvents[i]); var defaultTime = default(Timestamp); var ioStartTimeProjection = diskActivities.Compose(da => da.InsertTime ?? defaultTime); var ioEndTimeProjection = diskActivities.Compose(da => da.CompleteTime ?? defaultTime); var validIoTimeProjection = diskActivities.Compose(da => da.InsertTime.HasValue && da.CompleteTime.HasValue); table.AddColumn(deviceIdColumn, diskActivities.Compose(da => da.DeviceId)); table.AddColumn(deviceNameColumn, diskActivities.Compose(da => da.DeviceName)); table.AddColumn(filepathColumn, diskActivities.Compose(da => da.Filepath)); table.AddColumn(threadIdColumn, diskActivities.Compose(da => da.ThreadId)); table.AddColumn(processIdColumn, diskActivities.Compose(da => da.ProcessId)); table.AddColumn(commandColumn, diskActivities.Compose(da => da.ProcessCommand)); table.AddColumn(errorColumn, diskActivities.Compose(da => da.Error)); table.AddColumn(ioTimeIsValidColumnConfiguration, validIoTimeProjection); table.AddColumn(sectorNumberColumn, diskActivities.Compose(da => da.SectorNumber)); // todo:can we pick up the sector size from the trace? table.AddColumn(diskOffsetColumn, diskActivities.Compose(da => new Bytes(da.SectorNumber * 512))); table.AddColumn(insertTimeColumn, ioStartTimeProjection); table.AddColumn(issueTimeColumn, diskActivities.Compose(da => da.IssueTime ?? defaultTime)); table.AddColumn(completeTimeColumn, ioEndTimeProjection); var diskActivitiesProj = diskActivities.Compose((da) => { if (da.CompleteTime.HasValue) { if (da.InsertTime.HasValue) { return(da.CompleteTime.Value - da.InsertTime.Value); } } return(TimestampDelta.Zero); }); table.AddColumn(ioTimeAvgColumn, diskActivitiesProj); { IProjection <int, Timestamp> viewportClippedStartTimeColumn = Projection.ClipTimeToViewport.Create(ioStartTimeProjection); IProjection <int, Timestamp> viewportClippedEndTimeColumn = Projection.ClipTimeToViewport.Create(ioEndTimeProjection); // Timestamp delta for the given disk activity during the viewport time range. IProjection <int, TimestampDelta> clippedTimeDeltaColumn = Projection.Select( viewportClippedEndTimeColumn, viewportClippedStartTimeColumn, new ReduceTimeSinceLastDiff(validIoTimeProjection)); table.AddColumn(clippedTimestampDeltaColumnConfiguration, clippedTimeDeltaColumn); // Percent of time consumed by the timestamp delta in the current viewport. /* IProjection<int, double> ioTimeWeightPercentColumn = * Projection.ClipTimeToViewport.CreatePercent(clippedTimeDeltaColumn);*/ /// table.AddColumn(weightedIOTimeColumn, ioTimeWeightPercentColumn); } table.AddColumn(sizeColumn, new DiskActivitySizeProjection(diskActivities)); // IOCount with no restriction on IOSize - Used to enable some of the graphs in analyzer table.AddColumn(countColumn, Projection.Constant <int>(1)); // todo: should we move the Azure specific columns here? // IOCount when IOSize is 8KB (such as in Azure local SSD throttling) table.AddColumn(countColumn_IOSize8kb, diskActivities.Compose(da => da.Size.HasValue && da.Size.Value.Bytes > 0 ? Math.Ceiling((float)da.Size.Value.Bytes / (8 * 1024)) : 1)); // IOCount when IOSize is 256KB (such as in Azure XStore throttling) table.AddColumn(countColumn_IOSize256kb, diskActivities.Compose(da => da.Size.HasValue && da.Size.Value.Bytes > 0 ? Math.Ceiling((float)da.Size.Value.Bytes / (256 * 1024)) : 1)); }
public static void BuildTable(ITableBuilder tableBuilder, IDataExtensionRetrieval tableData) { int maximumFieldCount = tableData.QueryOutput <int>( DataOutputPath.Create("Perf/GenericEvents/MaximumEventFieldCount")); var events = tableData.QueryOutput <ProcessedEventData <PerfGenericEvent> >( DataOutputPath.Create("Perf/GenericEvents/Events")); var tableGenerator = tableBuilder.SetRowCount((int)events.Count); var genericEventProjection = new GenericEventProjection(events); var eventNameColumn = new BaseDataColumn <string>( eventNameColumnConfig, genericEventProjection.Compose((genericEvent) => genericEvent.EventName)); tableGenerator.AddColumn(eventNameColumn); var eventIdColumn = new BaseDataColumn <uint>( eventIdColumnConfig, genericEventProjection.Compose((genericEvent) => genericEvent.Id)); tableGenerator.AddColumn(eventIdColumn); var cpuIdColumn = new BaseDataColumn <uint>( cpuIdColumnConfig, genericEventProjection.Compose((genericEvent) => genericEvent.CpuId)); tableGenerator.AddColumn(cpuIdColumn); var eventTimestampColumn = new BaseDataColumn <Timestamp>( eventTimestampColumnConfig, genericEventProjection.Compose((genericEvent) => genericEvent.Timestamp)); tableGenerator.AddColumn(eventTimestampColumn); tableGenerator.AddColumn(countColumnConfig, Projection.Constant(1)); // Add the field columns, with column names depending on the given event for (int columnIndex = 0; columnIndex < maximumFieldCount; columnIndex++) { string fieldName = "Field " + (columnIndex + 1); var genericEventFieldProjection = new GenericEventFieldProjection(columnIndex, genericEventProjection); var genericEventFieldNameProjection = genericEventFieldProjection.Compose((field) => field.HasValue ? field.Value.Name : string.Empty); // generate a column configuration var fieldColumnConfiguration = new ColumnConfiguration( new ColumnMetadata(GenerateGuidFromName(fieldName), fieldName, genericEventFieldNameProjection, fieldName), new UIHints { IsVisible = true, Width = 80, TextAlignment = TextAlignment.Left, }); var genericEventFieldAsStringProjection = genericEventFieldProjection.Compose((field) => field.HasValue ? field.Value.Value : string.Empty); tableGenerator.AddColumn(fieldColumnConfiguration, genericEventFieldAsStringProjection); } }
public static void BuildTable(ITableBuilder tableBuilder, IDataExtensionRetrieval tableData) { // Get data from the cooker var events = tableData.QueryOutput <ProcessedEventData <PerfettoCpuCountersEvent> >( new DataOutputPath(PerfettoPluginConstants.CpuCountersEventCookerPath, nameof(PerfettoCpuCountersEventCooker.CpuCountersEvents))); var tableGenerator = tableBuilder.SetRowCount((int)events.Count); var baseProjection = Projection.Index(events); tableGenerator.AddColumn(CpuNumColumn, baseProjection.Compose(x => x.CpuNum)); tableGenerator.AddColumn(StartTimestampColumn, baseProjection.Compose(x => x.StartTimestamp)); tableGenerator.AddColumn(DurationColumn, baseProjection.Compose(x => x.Duration)); tableGenerator.AddColumn(UserPercentColumn, baseProjection.Compose(x => x.UserPercent)); tableGenerator.AddColumn(UserNicePercentColumn, baseProjection.Compose(x => x.UserNicePercent)); tableGenerator.AddColumn(SystemModePercentColumn, baseProjection.Compose(x => x.SystemModePercent)); tableGenerator.AddColumn(IdlePercentColumn, baseProjection.Compose(x => x.IdlePercent)); tableGenerator.AddColumn(IoWaitPercentColumn, baseProjection.Compose(x => x.IoWaitPercent)); tableGenerator.AddColumn(IrqPercentColumn, baseProjection.Compose(x => x.IrqPercent)); tableGenerator.AddColumn(SoftIrqPercentColumn, baseProjection.Compose(x => x.SoftIrqPercent)); tableGenerator.AddColumn(TotalCpuUsagePercentColumn, baseProjection.Compose(x => x.CpuPercent)); tableGenerator.AddColumn(CountColumn, Projection.Constant <int>(1)); // Only display the total CPU usage column var cpuUsageConfig = new TableConfiguration("CPU Usage %") { Columns = new[] { CpuNumColumn, TableConfiguration.PivotColumn, // Columns before this get pivotted on CountColumn, StartTimestampColumn, DurationColumn, UserPercentColumn, UserNicePercentColumn, SystemModePercentColumn, IdlePercentColumn, IoWaitPercentColumn, IrqPercentColumn, SoftIrqPercentColumn, TableConfiguration.GraphColumn, // Columns after this get graphed TotalCpuUsagePercentColumn }, ChartType = ChartType.Line }; cpuUsageConfig.AddColumnRole(ColumnRole.StartTime, StartTimestampColumn.Metadata.Guid); cpuUsageConfig.AddColumnRole(ColumnRole.ResourceId, CpuNumColumn); cpuUsageConfig.AddColumnRole(ColumnRole.Duration, DurationColumn); // Display all CPU counter columns var allCountersConfig = new TableConfiguration("CPU Counters - All") { Columns = new[] { CpuNumColumn, TableConfiguration.PivotColumn, // Columns before this get pivotted on CountColumn, StartTimestampColumn, DurationColumn, TotalCpuUsagePercentColumn, IdlePercentColumn, TableConfiguration.GraphColumn, // Columns after this get graphed UserPercentColumn, UserNicePercentColumn, SystemModePercentColumn, IoWaitPercentColumn, IrqPercentColumn, SoftIrqPercentColumn, }, ChartType = ChartType.Line }; allCountersConfig.AddColumnRole(ColumnRole.StartTime, StartTimestampColumn.Metadata.Guid); allCountersConfig.AddColumnRole(ColumnRole.ResourceId, CpuNumColumn); allCountersConfig.AddColumnRole(ColumnRole.Duration, DurationColumn); tableBuilder.AddTableConfiguration(cpuUsageConfig) .AddTableConfiguration(allCountersConfig) .SetDefaultTableConfiguration(cpuUsageConfig); }