Perfetto plugin - Added tables for per-process memory and system memory (#35)

Added table that displays memory for each process based on /proc//status
Added table that displays overall system memory based on /proc/meminfo
Reorganized table groups into "Perfetto - Android", "Perfetto - Events", and "Perfetto - System"
Reorganized namespaces and PerfettoPluginConstants
This commit is contained in:
Kyle Storck 2021-09-02 15:14:24 -06:00 коммит произвёл GitHub
Родитель 52a1f4c2a1
Коммит 5e97a0749d
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
36 изменённых файлов: 1056 добавлений и 53 удалений

Просмотреть файл

@ -8,9 +8,10 @@ using Microsoft.Performance.SDK.Extensibility;
using Microsoft.Performance.SDK.Extensibility.DataCooking;
using Microsoft.Performance.SDK.Processing;
using PerfettoCds.Pipeline.DataOutput;
using PerfettoCds.Pipeline.SourceDataCookers;
using PerfettoProcessor;
namespace PerfettoCds.Pipeline.DataCookers
namespace PerfettoCds.Pipeline.CompositeDataCookers
{
/// <summary>
/// Pulls data from multiple individual SQL tables and joins them to create a CPU counters event.

Просмотреть файл

@ -8,9 +8,10 @@ using Microsoft.Performance.SDK.Extensibility;
using Microsoft.Performance.SDK.Extensibility.DataCooking;
using Microsoft.Performance.SDK.Processing;
using PerfettoCds.Pipeline.DataOutput;
using PerfettoCds.Pipeline.SourceDataCookers;
using PerfettoProcessor;
namespace PerfettoCds.Pipeline.DataCookers
namespace PerfettoCds.Pipeline.CompositeDataCookers
{
/// <summary>
/// Pulls data from multiple individual SQL tables and joins them to create a a CPU frequency event. CPU frequency events

Просмотреть файл

@ -8,9 +8,10 @@ using Microsoft.Performance.SDK.Extensibility;
using Microsoft.Performance.SDK.Extensibility.DataCooking;
using Microsoft.Performance.SDK.Processing;
using PerfettoCds.Pipeline.DataOutput;
using PerfettoCds.Pipeline.SourceDataCookers;
using PerfettoProcessor;
namespace PerfettoCds.Pipeline.DataCookers
namespace PerfettoCds.Pipeline.CompositeDataCookers
{
/// <summary>
/// Pulls data from multiple individual SQL tables and joins them to create a CPU scheduling event

Просмотреть файл

@ -8,9 +8,10 @@ using Microsoft.Performance.SDK.Extensibility;
using Microsoft.Performance.SDK.Extensibility.DataCooking;
using Microsoft.Performance.SDK.Processing;
using PerfettoCds.Pipeline.DataOutput;
using PerfettoCds.Pipeline.SourceDataCookers;
using PerfettoProcessor;
namespace PerfettoCds.Pipeline.DataCookers
namespace PerfettoCds.Pipeline.CompositeDataCookers
{
/// <summary>
/// Pulls data from multiple individual SQL tables and joins them to create an Ftrace Perfetto event

Просмотреть файл

@ -13,8 +13,9 @@ using PerfettoProcessor;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
using PerfettoCds.Pipeline.SourceDataCookers;
namespace PerfettoCds.Pipeline.DataCookers
namespace PerfettoCds.Pipeline.CompositeDataCookers
{
/// <summary>
/// XML deserialized EventProvider

Просмотреть файл

@ -8,9 +8,10 @@ using Microsoft.Performance.SDK.Extensibility;
using Microsoft.Performance.SDK.Extensibility.DataCooking;
using Microsoft.Performance.SDK.Processing;
using PerfettoCds.Pipeline.DataOutput;
using PerfettoCds.Pipeline.SourceDataCookers;
using PerfettoProcessor;
namespace PerfettoCds.Pipeline.DataCookers
namespace PerfettoCds.Pipeline.CompositeDataCookers
{
/// <summary>
/// Pulls data from multiple individual SQL tables and joins them to create events for logcat output

Просмотреть файл

@ -0,0 +1,133 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Performance.SDK;
using Microsoft.Performance.SDK.Extensibility;
using Microsoft.Performance.SDK.Extensibility.DataCooking;
using Microsoft.Performance.SDK.Processing;
using PerfettoCds.Pipeline.DataOutput;
using PerfettoCds.Pipeline.SourceDataCookers;
using PerfettoProcessor;
namespace PerfettoCds.Pipeline.CompositeDataCookers
{
/// <summary>
/// Pulls data from multiple individual SQL tables and joins them to create a process memory event. Process
/// memory events list different memory counts per process
/// </summary>
public sealed class PerfettoProcessMemoryEventCooker : CookedDataReflector, ICompositeDataCookerDescriptor
{
public static readonly DataCookerPath DataCookerPath = PerfettoPluginConstants.ProcessMemoryEventCookerPath;
public string Description => "Process memory composite cooker";
public DataCookerPath Path => DataCookerPath;
// Declare all of the cookers that are used by this CompositeCooker.
public IReadOnlyCollection<DataCookerPath> RequiredDataCookers => new[]
{
PerfettoPluginConstants.CounterCookerPath,
PerfettoPluginConstants.ProcessCounterTrackCookerPath,
PerfettoPluginConstants.ProcessCookerPath
};
[DataOutput]
public ProcessedEventData<PerfettoProcessMemoryEvent> ProcessMemoryEvents { get; }
public PerfettoProcessMemoryEventCooker() : base(PerfettoPluginConstants.ProcessMemoryEventCookerPath)
{
this.ProcessMemoryEvents =
new ProcessedEventData<PerfettoProcessMemoryEvent>();
}
public void OnDataAvailable(IDataExtensionRetrieval requiredData)
{
// Gather the data from all the SQL tables
var counterData = requiredData.QueryOutput<ProcessedEventData<PerfettoCounterEvent>>(new DataOutputPath(PerfettoPluginConstants.CounterCookerPath, nameof(PerfettoCounterCooker.CounterEvents)));
var processCounterTrackData = requiredData.QueryOutput<ProcessedEventData<PerfettoProcessCounterTrackEvent>>(new DataOutputPath(PerfettoPluginConstants.ProcessCounterTrackCookerPath, nameof(PerfettoProcessCounterTrackCooker.ProcessCounterTrackEvents)));
var processData = requiredData.QueryOutput<ProcessedEventData<PerfettoProcessEvent>>(new DataOutputPath(PerfettoPluginConstants.ProcessCookerPath, nameof(PerfettoProcessCooker.ProcessEvents)));
// Join them all together
// Counter table contains the memory count value, timestamp
// ProcessCounterTrack contains the UPID and memory type name. All the memory types we care about start with "mem."
// Process contains the process name
var joined = from counter in counterData
join processCounterTrack in processCounterTrackData on counter.TrackId equals processCounterTrack.Id
join process in processData on processCounterTrack.Upid equals process.Upid
where processCounterTrack.Name.StartsWith("mem.")
orderby counter.Timestamp ascending
select new { counter, processCounterTrack, process };
// Create events out of the joined results
foreach (var processGroup in joined.GroupBy(x => x.processCounterTrack.Upid))
{
var timeGroups = processGroup.GroupBy(z => z.counter.RelativeTimestamp);
for (int i = 0; i < timeGroups.Count(); i++)
{
var timeGroup = timeGroups.ElementAt(i);
var ts = timeGroup.Key;
var processName = $"{timeGroup.ElementAt(0).process.Name} {processGroup.Key}";
long nextTs = ts;
if (i < timeGroups.Count() - 1)
{
// Need to look ahead in the future at the next event to get the timestamp so that we can calculate the duration
nextTs = timeGroups.ElementAt(i + 1).Key;
}
double virt = 0.0, rss = 0.0, rssAnon = 0.0, rssFile = 0.0, rssShMem = 0.0, rssHwm = 0.0, swap = 0.0, locked = 0.0;
// Gather each type of memory
foreach (var thing in timeGroup)
{
switch (thing.processCounterTrack.Name)
{
case "mem.virt":
virt = thing.counter.FloatValue;
break;
case "mem.rss":
rss = thing.counter.FloatValue;
break;
case "mem.rss.anon":
rssAnon = thing.counter.FloatValue;
break;
case "mem.rss.file":
rssFile = thing.counter.FloatValue;
break;
case "mem.rss.shmem":
rssShMem = thing.counter.FloatValue;
break;
case "mem.rss.watermark":
rssHwm = thing.counter.FloatValue;
break;
case "mem.locked":
locked = thing.counter.FloatValue;
break;
case "mem.swap":
swap = thing.counter.FloatValue;
break;
}
}
PerfettoProcessMemoryEvent ev = new PerfettoProcessMemoryEvent
(
processName,
new Timestamp(ts),
new TimestampDelta(nextTs - ts),
rssAnon,
rssShMem,
rssFile,
rssHwm,
rss,
locked,
swap,
virt
);
this.ProcessMemoryEvents.AddEvent(ev);
}
}
this.ProcessMemoryEvents.FinalizeData();
}
}
}

Просмотреть файл

@ -0,0 +1,132 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Performance.SDK;
using Microsoft.Performance.SDK.Extensibility;
using Microsoft.Performance.SDK.Extensibility.DataCooking;
using Microsoft.Performance.SDK.Processing;
using PerfettoCds.Pipeline.DataOutput;
using PerfettoCds.Pipeline.SourceDataCookers;
using PerfettoProcessor;
namespace PerfettoCds.Pipeline.CompositeDataCookers
{
/// <summary>
/// Pulls data from multiple individual SQL tables and joins them to create a system memory event. System
/// memory events capture periodic system memory counts
/// </summary>
public sealed class PerfettoSystemMemoryEventCooker : CookedDataReflector, ICompositeDataCookerDescriptor
{
public static readonly DataCookerPath DataCookerPath = PerfettoPluginConstants.SystemMemoryEventCookerPath;
public string Description => "System memory composite cooker";
public DataCookerPath Path => DataCookerPath;
// Declare all of the cookers that are used by this CompositeCooker.
public IReadOnlyCollection<DataCookerPath> RequiredDataCookers => new[]
{
PerfettoPluginConstants.CounterCookerPath,
PerfettoPluginConstants.CounterTrackCookerPath
};
[DataOutput]
public ProcessedEventData<PerfettoSystemMemoryEvent> SystemMemoryEvents { get; }
// Perfetto captures memory counts from /proc/meminfo and outputs events with
// the following names.
// Set sys_stats_counters.h in Perfetto repo.
public HashSet<string> MemoryTypes = new HashSet<string>() {
"MemUnspecified",
"MemTotal",
"MemFree",
"MemAvailable",
"Buffers",
"Cached",
"SwapCached",
"Active",
"Inactive",
"Active(anon)",
"Inactive(anon)",
"Active(file)",
"Inactive(file)",
"Unevictable",
"Mlocked",
"SwapTotal",
"SwapFree",
"Dirty",
"Writeback",
"AnonPages",
"Mapped",
"Shmem",
"Slab",
"SReclaimable",
"SUnreclaim",
"KernelStack",
"PageTables",
"CommitLimit",
"Committed_AS",
"VmallocTotal",
"VmallocUsed",
"VmallocChunk",
"CmaTotal",
"CmaFree"
};
public PerfettoSystemMemoryEventCooker() : base(PerfettoPluginConstants.SystemMemoryEventCookerPath)
{
this.SystemMemoryEvents =
new ProcessedEventData<PerfettoSystemMemoryEvent>();
}
public void OnDataAvailable(IDataExtensionRetrieval requiredData)
{
// Gather the data from all the SQL tables
var counterData = requiredData.QueryOutput<ProcessedEventData<PerfettoCounterEvent>>(new DataOutputPath(PerfettoPluginConstants.CounterCookerPath, nameof(PerfettoCounterCooker.CounterEvents)));
var counterTrackData = requiredData.QueryOutput<ProcessedEventData<PerfettoCounterTrackEvent>>(new DataOutputPath(PerfettoPluginConstants.CounterTrackCookerPath, nameof(PerfettoCounterTrackCooker.CounterTrackEvents)));
// Join them all together
// Counter table contains the memory count value, timestamp
// counterTrackData contains the name of the memory type
// Process contains the process name
var joined = from counter in counterData
join counterTrack in counterTrackData on counter.TrackId equals counterTrack.Id
where MemoryTypes.Contains(counterTrack.Name)
orderby counter.Timestamp ascending
select new { counter, counterTrack };
// Create events out of the joined results
foreach (var memoryGroup in joined.GroupBy(x => x.counterTrack.Name))
{
string memoryType = memoryGroup.Key;
for(int i = 0; i < memoryGroup.Count(); i++)
{
var thing = memoryGroup.ElementAt(i);
double val = thing.counter.FloatValue;
var ts = thing.counter.RelativeTimestamp;
long nextTs = ts;
if (i < memoryGroup.Count() - 1)
{
// Need to look ahead in the future at the next event to get the timestamp so that we can calculate the duration
nextTs = memoryGroup.ElementAt(i + 1).counter.RelativeTimestamp;
}
PerfettoSystemMemoryEvent ev = new PerfettoSystemMemoryEvent
(
val,
memoryType,
new Timestamp(ts),
new TimestampDelta(nextTs - ts)
);
this.SystemMemoryEvents.AddEvent(ev);
}
}
this.SystemMemoryEvents.FinalizeData();
}
}
}

Просмотреть файл

@ -0,0 +1,58 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.Performance.SDK;
using System.Collections.Generic;
namespace PerfettoCds.Pipeline.DataOutput
{
/// <summary>
/// A event that represents several memory values for a process at a point in time
/// </summary>
public readonly struct PerfettoProcessMemoryEvent
{
public string ProcessName { get; }
public Timestamp StartTimestamp { get; }
public TimestampDelta Duration { get; }
/// Resident set size - anonymous memory
public double RssAnon { get; }
/// Resident set size - shared memory
public double RssShMem { get; }
/// Resident set size - file mappings
public double RssFile { get; }
/// Resident set size - Peak (high water mark)
public double RssHwm { get; }
/// Resident set size - Sum of anon, file, ShMem
public double Rss { get; }
/// Locked memory size
public double Locked { get; }
/// Swapped out VM size by anonymous private pages
public double Swap { get; }
/// Peak virtual memory size
public double Virt { get; }
public PerfettoProcessMemoryEvent(string processName, Timestamp startTimestamp, TimestampDelta duration,
double rssAnon,
double rssShMem,
double rssFile,
double rssHwm,
double rss,
double locked,
double swap,
double virt)
{
this.ProcessName = processName;
this.StartTimestamp = startTimestamp;
this.Duration = duration;
this.RssAnon = rssAnon;
this.Locked = locked;
this.RssShMem = rssShMem;
this.RssFile = rssFile;
this.RssHwm = rssHwm;
this.Rss = rss;
this.Swap = swap;
this.Virt = virt;
}
}
}

Просмотреть файл

@ -0,0 +1,26 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.Performance.SDK;
using System.Collections.Generic;
namespace PerfettoCds.Pipeline.DataOutput
{
/// <summary>
/// A event that represents a single system memory value at a point in time
/// </summary>
public readonly struct PerfettoSystemMemoryEvent
{
public double Value { get; }
public string MemoryType { get; }
public Timestamp StartTimestamp { get; }
public TimestampDelta Duration { get; }
public PerfettoSystemMemoryEvent(double value, string memoryType, Timestamp startTimestamp, TimestampDelta duration)
{
this.Value = value;
this.MemoryType = memoryType;
this.StartTimestamp = startTimestamp;
this.Duration = duration;
}
}
}

Просмотреть файл

@ -1,6 +1,9 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.Performance.SDK.Extensibility;
using PerfettoCds.Pipeline.CompositeDataCookers;
using PerfettoCds.Pipeline.SourceDataCookers;
using PerfettoCds.Pipeline.DataOutput;
using PerfettoProcessor;
namespace PerfettoCds
@ -13,24 +16,28 @@ namespace PerfettoCds
public const string ParserId = "PerfettoSourceParser";
// ID for source data cookers
public const string SliceCookerId = "PerfettoSliceCooker";
public const string ArgCookerId = "PerfettoArgCooker";
public const string ThreadCookerId = "PerfettoThreadCooker";
public const string ThreadTrackCookerId = "PerfettoThreadCookerId";
public const string ProcessCookerId = "PerfettoProcessCooker";
public const string SchedSliceCookerId = "PerfettoSchedSliceCooker";
public const string AndroidLogCookerId = "PerfettoAndroidLogCooker";
public const string RawCookerId = "PerfettoRawCooker";
public const string CounterCookerId = "PerfettoCounterCooker";
public const string CpuCounterTrackCookerId = "PerfettoCpuCounterTrackCooker";
public const string SliceCookerId = nameof(PerfettoSliceCooker);
public const string ArgCookerId = nameof(PerfettoArgCooker);
public const string ThreadCookerId = nameof(PerfettoThreadCooker);
public const string ThreadTrackCookerId = nameof(PerfettoThreadTrackCooker);
public const string ProcessCookerId = nameof(PerfettoProcessCooker);
public const string SchedSliceCookerId = nameof(PerfettoSchedSliceCooker);
public const string AndroidLogCookerId = nameof(PerfettoAndroidLogCooker);
public const string RawCookerId = nameof(PerfettoRawCooker);
public const string CounterCookerId = nameof(PerfettoCounterCooker);
public const string CpuCounterTrackCookerId = nameof(PerfettoCpuCounterTrackCooker);
public const string ProcessCounterTrackCookerId = nameof(PerfettoProcessCounterTrackCooker);
public const string CounterTrackCookerId = nameof(PerfettoCounterTrackCooker);
// ID for composite data cookers
public const string GenericEventCookerId = "PerfettoGenericEventCooker";
public const string CpuSchedEventCookerId = "PerfettoCpuSchedEventCooker";
public const string LogcatEventCookerId = "PerfettoLogcatEventCooker";
public const string FtraceEventCookerId = "PerfettoFtraceEventCooker";
public const string CpuFrequencyEventCookerId = "PerfettoCpuFrequencyEventCooker";
public const string CpuCountersEventCookerId = "PerfettoCpuCountersEventCooker";
public const string GenericEventCookerId = nameof(PerfettoGenericEventCooker);
public const string CpuSchedEventCookerId = nameof(PerfettoCpuSchedEventCooker);
public const string LogcatEventCookerId = nameof(PerfettoLogcatEventCooker);
public const string FtraceEventCookerId = nameof(PerfettoFtraceEventCooker);
public const string CpuFrequencyEventCookerId = nameof(PerfettoCpuFrequencyEventCooker);
public const string CpuCountersEventCookerId = nameof(PerfettoCpuCountersEventCooker);
public const string ProcessMemoryEventCookerId = nameof(PerfettoProcessMemoryEventCooker);
public const string SystemMemoryEventCookerId = nameof(PerfettoSystemMemoryEventCooker);
// Events for source cookers
public const string SliceEvent = PerfettoSliceEvent.Key;
@ -43,14 +50,18 @@ namespace PerfettoCds
public const string RawEvent = PerfettoRawEvent.Key;
public const string CounterEvent = PerfettoCounterEvent.Key;
public const string CpuCounterTrackEvent = PerfettoCpuCounterTrackEvent.Key;
public const string ProcessCounterTrackEvent = PerfettoProcessCounterTrackEvent.Key;
public const string CounterTrackEvent = PerfettoCounterTrackEvent.Key;
// Output events for composite cookers
public const string GenericEvent = "PerfettoGenericEvent";
public const string CpuSchedEvent = "PerfettoCpuSchedEvent";
public const string LogcatEvent = "PerfettoLogcatEvent";
public const string FtraceEvent = "PerfettoFtraceEvent";
public const string CpuFrequencyEvent = "PerfettoCpuFrequencyEvent";
public const string CpuCountersEvent = "PerfettoCpuCountersEvent";
public const string GenericEvent = nameof(PerfettoGenericEvent);
public const string CpuSchedEvent = nameof(PerfettoCpuSchedEvent);
public const string LogcatEvent = nameof(PerfettoLogcatEvent);
public const string FtraceEvent = nameof(PerfettoFtraceEvent);
public const string CpuFrequencyEvent = nameof(PerfettoCpuFrequencyEvent);
public const string CpuCountersEvent = nameof(PerfettoCpuCountersEvent);
public const string ProcessMemoryEvent = nameof(PerfettoProcessMemoryEvent);
public const string SystemMemoryEvent = nameof(PerfettoSystemMemoryEvent);
// Paths for source cookers
public static readonly DataCookerPath SliceCookerPath =
@ -73,6 +84,10 @@ namespace PerfettoCds
new DataCookerPath(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.CounterCookerId);
public static readonly DataCookerPath CpuCounterTrackCookerPath =
new DataCookerPath(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.CpuCounterTrackCookerId);
public static readonly DataCookerPath ProcessCounterTrackCookerPath =
new DataCookerPath(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.ProcessCounterTrackCookerId);
public static readonly DataCookerPath CounterTrackCookerPath =
new DataCookerPath(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.CounterTrackCookerId);
// Paths for composite cookers
public static readonly DataCookerPath GenericEventCookerPath =
@ -87,6 +102,10 @@ namespace PerfettoCds
new DataCookerPath(PerfettoPluginConstants.CpuFrequencyEventCookerId);
public static readonly DataCookerPath CpuCountersEventCookerPath =
new DataCookerPath(PerfettoPluginConstants.CpuCountersEventCookerId);
public static readonly DataCookerPath ProcessMemoryEventCookerPath =
new DataCookerPath(PerfettoPluginConstants.ProcessMemoryEventCookerId);
public static readonly DataCookerPath SystemMemoryEventCookerPath =
new DataCookerPath(PerfettoPluginConstants.SystemMemoryEventCookerId);
}
}

Просмотреть файл

@ -163,7 +163,9 @@ namespace PerfettoCds
new PerfettoAndroidLogEvent(),
new PerfettoRawEvent(),
new PerfettoCpuCounterTrackEvent(),
new PerfettoCounterEvent()
new PerfettoCounterEvent(),
new PerfettoProcessCounterTrackEvent(),
new PerfettoCounterTrackEvent()
};
// Increment progress for each table queried.

Просмотреть файл

@ -10,7 +10,7 @@ using System.Threading;
using PerfettoCds.Pipeline.Events;
using PerfettoProcessor;
namespace PerfettoCds
namespace PerfettoCds.Pipeline.SourceDataCookers
{
/// <summary>
/// Cooks the data from the Android_Logs table in Perfetto traces

Просмотреть файл

@ -10,7 +10,7 @@ using System.Threading;
using PerfettoCds.Pipeline.Events;
using PerfettoProcessor;
namespace PerfettoCds
namespace PerfettoCds.Pipeline.SourceDataCookers
{
/// <summary>
/// Cooks the data from the Args table in Perfetto traces

Просмотреть файл

@ -10,7 +10,7 @@ using System.Threading;
using PerfettoCds.Pipeline.Events;
using PerfettoProcessor;
namespace PerfettoCds
namespace PerfettoCds.Pipeline.SourceDataCookers
{
/// <summary>
/// Cooks the data from the Counter table in Perfetto traces

Просмотреть файл

@ -0,0 +1,52 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.Performance.SDK;
using Microsoft.Performance.SDK.Extensibility;
using Microsoft.Performance.SDK.Extensibility.DataCooking;
using Microsoft.Performance.SDK.Extensibility.DataCooking.SourceDataCooking;
using Microsoft.Performance.SDK.Processing;
using System.Collections.Generic;
using System.Threading;
using PerfettoCds.Pipeline.Events;
using PerfettoProcessor;
namespace PerfettoCds.Pipeline.SourceDataCookers
{
/// <summary>
/// Cooks the data from the CounterTrack table in Perfetto traces
/// </summary>
public sealed class PerfettoCounterTrackCooker : BaseSourceDataCooker<PerfettoSqlEventKeyed, PerfettoSourceParser, string>
{
public override string Description => "Processes events from the counter_track Perfetto SQL table";
//
// The data this cooker outputs. Tables or other cookers can query for this data
// via the SDK runtime
//
[DataOutput]
public ProcessedEventData<PerfettoCounterTrackEvent> CounterTrackEvents { get; }
// Instructs runtime to only send events with the given keys this data cooker
public override ReadOnlyHashSet<string> DataKeys =>
new ReadOnlyHashSet<string>(new HashSet<string> { PerfettoPluginConstants.CounterTrackEvent });
public PerfettoCounterTrackCooker() : base(PerfettoPluginConstants.CounterTrackCookerPath)
{
this.CounterTrackEvents = new ProcessedEventData<PerfettoCounterTrackEvent>();
}
public override DataProcessingResult CookDataElement(PerfettoSqlEventKeyed perfettoEvent, PerfettoSourceParser context, CancellationToken cancellationToken)
{
var newEvent = (PerfettoCounterTrackEvent)perfettoEvent.SqlEvent;
this.CounterTrackEvents.AddEvent(newEvent);
return DataProcessingResult.Processed;
}
public override void EndDataCooking(CancellationToken cancellationToken)
{
base.EndDataCooking(cancellationToken);
this.CounterTrackEvents.FinalizeData();
}
}
}

Просмотреть файл

@ -10,7 +10,7 @@ using System.Threading;
using PerfettoCds.Pipeline.Events;
using PerfettoProcessor;
namespace PerfettoCds
namespace PerfettoCds.Pipeline.SourceDataCookers
{
/// <summary>
/// Cooks the data from the CpuCounterTrack table in Perfetto traces

Просмотреть файл

@ -10,7 +10,7 @@ using System.Threading;
using PerfettoCds.Pipeline.Events;
using PerfettoProcessor;
namespace PerfettoCds
namespace PerfettoCds.Pipeline.SourceDataCookers
{
/// <summary>
/// Cooks the data from the Process table in Perfetto traces

Просмотреть файл

@ -0,0 +1,53 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.Performance.SDK;
using Microsoft.Performance.SDK.Extensibility;
using Microsoft.Performance.SDK.Extensibility.DataCooking;
using Microsoft.Performance.SDK.Extensibility.DataCooking.SourceDataCooking;
using Microsoft.Performance.SDK.Processing;
using System.Collections.Generic;
using System.Threading;
using PerfettoCds.Pipeline.Events;
using PerfettoProcessor;
namespace PerfettoCds.Pipeline.SourceDataCookers
{
/// <summary>
/// Cooks the data from the ProcessCounterTrack table in Perfetto traces
/// </summary>
public sealed class PerfettoProcessCounterTrackCooker : BaseSourceDataCooker<PerfettoSqlEventKeyed, PerfettoSourceParser, string>
{
public override string Description => "Processes events from the process_counter_track Perfetto SQL table";
//
// The data this cooker outputs. Tables or other cookers can query for this data
// via the SDK runtime
//
[DataOutput]
public ProcessedEventData<PerfettoProcessCounterTrackEvent> ProcessCounterTrackEvents { get; }
// Instructs runtime to only send events with the given keys this data cooker
public override ReadOnlyHashSet<string> DataKeys =>
new ReadOnlyHashSet<string>(new HashSet<string> { PerfettoPluginConstants.ProcessCounterTrackEvent });
public PerfettoProcessCounterTrackCooker() : base(PerfettoPluginConstants.ProcessCounterTrackCookerPath)
{
this.ProcessCounterTrackEvents =
new ProcessedEventData<PerfettoProcessCounterTrackEvent>();
}
public override DataProcessingResult CookDataElement(PerfettoSqlEventKeyed perfettoEvent, PerfettoSourceParser context, CancellationToken cancellationToken)
{
this.ProcessCounterTrackEvents.AddEvent((PerfettoProcessCounterTrackEvent)perfettoEvent.SqlEvent);
return DataProcessingResult.Processed;
}
public override void EndDataCooking(CancellationToken cancellationToken)
{
base.EndDataCooking(cancellationToken);
this.ProcessCounterTrackEvents.FinalizeData();
}
}
}

Просмотреть файл

@ -10,7 +10,7 @@ using System.Threading;
using PerfettoCds.Pipeline.Events;
using PerfettoProcessor;
namespace PerfettoCds
namespace PerfettoCds.Pipeline.SourceDataCookers
{
/// <summary>
/// Cooks the data from the Raw table in Perfetto traces

Просмотреть файл

@ -10,7 +10,7 @@ using System.Threading;
using PerfettoCds.Pipeline.Events;
using PerfettoProcessor;
namespace PerfettoCds
namespace PerfettoCds.Pipeline.SourceDataCookers
{
/// <summary>
/// Cooks the data from the SchedSlice table in Perfetto traces

Просмотреть файл

@ -10,7 +10,7 @@ using System.Threading;
using PerfettoCds.Pipeline.Events;
using PerfettoProcessor;
namespace PerfettoCds
namespace PerfettoCds.Pipeline.SourceDataCookers
{
/// <summary>
/// Cooks the data from the Slice table in Perfetto traces

Просмотреть файл

@ -10,7 +10,7 @@ using System.Threading;
using PerfettoCds.Pipeline.Events;
using PerfettoProcessor;
namespace PerfettoCds
namespace PerfettoCds.Pipeline.SourceDataCookers
{
/// <summary>
/// Cooks the data from the Thread table in Perfetto traces

Просмотреть файл

@ -10,7 +10,7 @@ using System.Threading;
using PerfettoCds.Pipeline.Events;
using PerfettoProcessor;
namespace PerfettoCds
namespace PerfettoCds.Pipeline.SourceDataCookers
{
/// <summary>
/// Cooks the data from the ThreadTrack table in Perfetto traces

Просмотреть файл

@ -8,7 +8,7 @@ using System.Security.Cryptography;
using System.Diagnostics.CodeAnalysis;
using PerfettoCds.Pipeline.DataOutput;
using Microsoft.Performance.SDK;
using PerfettoCds.Pipeline.DataCookers;
using PerfettoCds.Pipeline.CompositeDataCookers;
using System.Linq;
namespace PerfettoCds.Pipeline.Tables
@ -20,7 +20,7 @@ namespace PerfettoCds.Pipeline.Tables
Guid.Parse("{cc2db5d6-5abb-4094-b8c0-475a2f4d9946}"),
"Perfetto CPU Counters (coarse)",
"Displays coarse CPU usage based on /proc/stat counters",
"Perfetto",
"Perfetto - System",
requiredDataCookers: new List<DataCookerPath> { PerfettoPluginConstants.CpuCountersEventCookerPath }
);
@ -123,7 +123,7 @@ namespace PerfettoCds.Pipeline.Tables
tableGenerator.AddColumn(CountColumn, Projection.Constant<int>(1));
// Only display the total CPU usage column
var cpuUsageConfig = new TableConfiguration("Perfetto CPU usage")
var cpuUsageConfig = new TableConfiguration("Perfetto CPU Usage")
{
Columns = new[]
{

Просмотреть файл

@ -8,7 +8,7 @@ using System.Security.Cryptography;
using System.Diagnostics.CodeAnalysis;
using PerfettoCds.Pipeline.DataOutput;
using Microsoft.Performance.SDK;
using PerfettoCds.Pipeline.DataCookers;
using PerfettoCds.Pipeline.CompositeDataCookers;
using System.Linq;
namespace PerfettoCds.Pipeline.Tables
@ -20,7 +20,7 @@ namespace PerfettoCds.Pipeline.Tables
Guid.Parse("{5b9689d4-617c-484c-9b0a-c7242565ec13}"),
"Perfetto CPU Frequency Scaling",
"Displays CPU frequency scaling events and idle states for CPUs. Idle CPUs show a frequency of 0.",
"Perfetto",
"Perfetto - System",
requiredDataCookers: new List<DataCookerPath> { PerfettoPluginConstants.CpuFrequencyEventCookerPath }
);

Просмотреть файл

@ -8,7 +8,7 @@ using System.Security.Cryptography;
using System.Diagnostics.CodeAnalysis;
using PerfettoCds.Pipeline.DataOutput;
using Microsoft.Performance.SDK;
using PerfettoCds.Pipeline.DataCookers;
using PerfettoCds.Pipeline.CompositeDataCookers;
using System.Linq;
namespace PerfettoCds.Pipeline.Tables
@ -20,7 +20,7 @@ namespace PerfettoCds.Pipeline.Tables
Guid.Parse("{db17169e-afe5-41f6-ba24-511af1d869f9}"),
"Perfetto CPU Scheduler Events",
"Displays CPU scheduling events for processes and threads",
"Perfetto",
"Perfetto - System",
requiredDataCookers: new List<DataCookerPath> { PerfettoPluginConstants.CpuSchedEventCookerPath }
);

Просмотреть файл

@ -6,7 +6,7 @@ using System;
using System.Collections.Generic;
using PerfettoCds.Pipeline.DataOutput;
using Microsoft.Performance.SDK;
using PerfettoCds.Pipeline.DataCookers;
using PerfettoCds.Pipeline.CompositeDataCookers;
using Utilities;
namespace PerfettoCds.Pipeline.Tables
@ -21,7 +21,7 @@ namespace PerfettoCds.Pipeline.Tables
Guid.Parse("{96beb7a0-5a9e-4713-b1f7-4ee74d27851c}"),
"Perfetto Ftrace Events",
"All Ftrace events in the Perfetto trace",
"Perfetto",
"Perfetto - Events",
requiredDataCookers: new List<DataCookerPath> { PerfettoPluginConstants.FtraceEventCookerPath }
);

Просмотреть файл

@ -6,7 +6,7 @@ using System;
using System.Collections.Generic;
using PerfettoCds.Pipeline.DataOutput;
using Microsoft.Performance.SDK;
using PerfettoCds.Pipeline.DataCookers;
using PerfettoCds.Pipeline.CompositeDataCookers;
using Utilities;
namespace PerfettoCds.Pipeline.Tables
@ -21,7 +21,7 @@ namespace PerfettoCds.Pipeline.Tables
Guid.Parse("{506777b6-f1a3-437a-b976-bc48190450b6}"),
"Perfetto Generic Events",
"All app/component events in the Perfetto trace",
"Perfetto",
"Perfetto - Events",
requiredDataCookers: new List<DataCookerPath> { PerfettoPluginConstants.GenericEventCookerPath }
);

Просмотреть файл

@ -8,7 +8,7 @@ using System.Security.Cryptography;
using System.Diagnostics.CodeAnalysis;
using PerfettoCds.Pipeline.DataOutput;
using Microsoft.Performance.SDK;
using PerfettoCds.Pipeline.DataCookers;
using PerfettoCds.Pipeline.CompositeDataCookers;
namespace PerfettoCds.Pipeline.Tables
{
@ -22,7 +22,7 @@ namespace PerfettoCds.Pipeline.Tables
Guid.Parse("{1b25fe8d-887c-4de9-850f-284eb4c28ad7}"),
"Android Logcat Events",
"All logcat events/messages in the Perfetto trace",
"Android",
"Perfetto - Android",
requiredDataCookers: new List<DataCookerPath> { PerfettoPluginConstants.LogcatEventCookerPath }
);

Просмотреть файл

@ -0,0 +1,304 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.Performance.SDK.Extensibility;
using Microsoft.Performance.SDK.Processing;
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Diagnostics.CodeAnalysis;
using PerfettoCds.Pipeline.DataOutput;
using Microsoft.Performance.SDK;
using PerfettoCds.Pipeline.CompositeDataCookers;
using System.Linq;
namespace PerfettoCds.Pipeline.Tables
{
[Table]
public class PerfettoProcessMemoryTable
{
public static TableDescriptor TableDescriptor => new TableDescriptor(
Guid.Parse("{80d5ef1d-a24f-472c-83be-707b03239d35}"),
"Perfetto Process Memory",
"Displays per process memory counts gathered from /proc/<pid>/status",
"Perfetto - System",
requiredDataCookers: new List<DataCookerPath> { PerfettoPluginConstants.ProcessMemoryEventCookerPath }
);
private static readonly ColumnConfiguration ProcessNameColumn = new ColumnConfiguration(
new ColumnMetadata(new Guid("{5f47812f-85ab-42e8-bae3-1e7bf377a689}"), "Process", "Process name"),
new UIHints { Width = 210 });
private static readonly ColumnConfiguration StartTimestampColumn = new ColumnConfiguration(
new ColumnMetadata(new Guid("{4b2c0e42-04ee-4e4f-916f-bf7065f34018}"), "StartTimestamp", "Start timestamp for the memory event"),
new UIHints { Width = 120 });
private static readonly ColumnConfiguration DurationColumn = new ColumnConfiguration(
new ColumnMetadata(new Guid("{1db8a444-3bcc-4787-bc4c-f8ffd25ccf98}"), "Duration", "Start timestamp for the memory sample"),
new UIHints { Width = 120 });
private static readonly ColumnConfiguration RssAnonColumn = new ColumnConfiguration(
new ColumnMetadata(new Guid("{59db9b2a-09aa-42c5-9da7-631a507f0dbc}"), "RssAnonymous(kb)", "Resident set size - anonymous memory"),
new UIHints { Width = 120, AggregationMode = AggregationMode.Max });
private static readonly ColumnConfiguration RssShMemColumn = new ColumnConfiguration(
new ColumnMetadata(new Guid("{2969f7a3-54b3-492c-a393-1bd937389bd2}"), "RssSharedMem(kb)", "Resident set size - shared memory"),
new UIHints { Width = 120, AggregationMode = AggregationMode.Max });
private static readonly ColumnConfiguration RssFileColumn = new ColumnConfiguration(
new ColumnMetadata(new Guid("{96a12428-279e-4ef7-830b-89268c1d90cf}"), "RssFile(kb)", "Resident set size - file mappings"),
new UIHints { Width = 120, AggregationMode = AggregationMode.Max });
private static readonly ColumnConfiguration RssHwmColumn = new ColumnConfiguration(
new ColumnMetadata(new Guid("{88f8d32e-c884-4263-9712-44166aee1f95}"), "RssHighWatermark(kb)", "Resident set size - peak (high water mark)"),
new UIHints { Width = 120, AggregationMode = AggregationMode.Max });
private static readonly ColumnConfiguration RssColumn = new ColumnConfiguration(
new ColumnMetadata(new Guid("{1ea71b65-4a32-4fc0-8a87-273073a51aa9}"), "Rss(kb)", "Resident set size - sum of anon, file, shared mem"),
new UIHints { Width = 120, AggregationMode = AggregationMode.Max });
private static readonly ColumnConfiguration LockedColumn = new ColumnConfiguration(
new ColumnMetadata(new Guid("{b9a65a94-f421-40cf-840e-74dffb84857f}"), "Locked(kb)", "Locked memory size"),
new UIHints { Width = 120, AggregationMode = AggregationMode.Max });
private static readonly ColumnConfiguration SwapColumn = new ColumnConfiguration(
new ColumnMetadata(new Guid("{f0ebf9e8-39a1-44b7-8bf0-5f11ff6a8089}"), "Swap(kb)", "Swapped out VM size by anonymous private pages"),
new UIHints { Width = 120, AggregationMode = AggregationMode.Max });
private static readonly ColumnConfiguration VirtColumn = new ColumnConfiguration(
new ColumnMetadata(new Guid("{83d575ba-2c24-46f7-901e-57241f72b918}"), "Virtual(kb)", "Peak virtual memory size"),
new UIHints { Width = 120, AggregationMode = AggregationMode.Max });
public static void BuildTable(ITableBuilder tableBuilder, IDataExtensionRetrieval tableData)
{
// Get data from the cooker
var events = tableData.QueryOutput<ProcessedEventData<PerfettoProcessMemoryEvent>>(
new DataOutputPath(PerfettoPluginConstants.ProcessMemoryEventCookerPath, nameof(PerfettoProcessMemoryEventCooker.ProcessMemoryEvents)));
var tableGenerator = tableBuilder.SetRowCount((int)events.Count);
var baseProjection = Projection.Index(events);
tableGenerator.AddColumn(StartTimestampColumn, baseProjection.Compose(x => x.StartTimestamp));
tableGenerator.AddColumn(ProcessNameColumn, baseProjection.Compose(x => x.ProcessName));
tableGenerator.AddColumn(DurationColumn, baseProjection.Compose(x => x.Duration));
tableGenerator.AddColumn(RssAnonColumn, baseProjection.Compose(x => x.RssAnon));
tableGenerator.AddColumn(LockedColumn, baseProjection.Compose(x => x.Locked));
tableGenerator.AddColumn(RssShMemColumn, baseProjection.Compose(x => x.RssShMem));
tableGenerator.AddColumn(RssFileColumn, baseProjection.Compose(x => x.RssFile));
tableGenerator.AddColumn(RssHwmColumn, baseProjection.Compose(x => x.RssHwm));
tableGenerator.AddColumn(RssColumn, baseProjection.Compose(x => x.Rss));
tableGenerator.AddColumn(SwapColumn, baseProjection.Compose(x => x.Swap));
tableGenerator.AddColumn(VirtColumn, baseProjection.Compose(x => x.Virt));
// Virtual
var virtConfig = new TableConfiguration("Virtual")
{
Columns = new[]
{
ProcessNameColumn,
TableConfiguration.PivotColumn, // Columns before this get pivotted on
StartTimestampColumn,
DurationColumn,
RssAnonColumn,
RssShMemColumn,
RssFileColumn,
RssHwmColumn,
RssColumn,
LockedColumn,
SwapColumn,
TableConfiguration.GraphColumn, // Columns after this get graphed
VirtColumn
},
Layout = TableLayoutStyle.GraphAndTable,
ChartType = ChartType.Line
};
virtConfig.AddColumnRole(ColumnRole.StartTime, StartTimestampColumn.Metadata.Guid);
virtConfig.AddColumnRole(ColumnRole.ResourceId, ProcessNameColumn);
virtConfig.AddColumnRole(ColumnRole.Duration, DurationColumn);
// Swap
var swapConfig = new TableConfiguration("Swap")
{
Columns = new[]
{
ProcessNameColumn,
TableConfiguration.PivotColumn, // Columns before this get pivotted on
StartTimestampColumn,
DurationColumn,
RssAnonColumn,
RssShMemColumn,
RssFileColumn,
RssHwmColumn,
RssColumn,
LockedColumn,
VirtColumn,
TableConfiguration.GraphColumn, // Columns after this get graphed
SwapColumn
},
Layout = TableLayoutStyle.GraphAndTable,
ChartType = ChartType.Line
};
swapConfig.AddColumnRole(ColumnRole.StartTime, StartTimestampColumn.Metadata.Guid);
swapConfig.AddColumnRole(ColumnRole.ResourceId, ProcessNameColumn);
swapConfig.AddColumnRole(ColumnRole.Duration, DurationColumn);
// Locked
var lockedConfig = new TableConfiguration("Locked")
{
Columns = new[]
{
ProcessNameColumn,
TableConfiguration.PivotColumn, // Columns before this get pivotted on
StartTimestampColumn,
DurationColumn,
RssAnonColumn,
RssShMemColumn,
RssFileColumn,
RssHwmColumn,
RssColumn,
SwapColumn,
VirtColumn,
TableConfiguration.GraphColumn, // Columns after this get graphed
LockedColumn
},
Layout = TableLayoutStyle.GraphAndTable,
ChartType = ChartType.Line
};
lockedConfig.AddColumnRole(ColumnRole.StartTime, StartTimestampColumn.Metadata.Guid);
lockedConfig.AddColumnRole(ColumnRole.ResourceId, ProcessNameColumn);
lockedConfig.AddColumnRole(ColumnRole.Duration, DurationColumn);
// Rss
var rssConfig = new TableConfiguration("RSS (sum of anon, file, shared mem)")
{
Columns = new[]
{
ProcessNameColumn,
TableConfiguration.PivotColumn, // Columns before this get pivotted on
StartTimestampColumn,
DurationColumn,
RssAnonColumn,
RssShMemColumn,
RssFileColumn,
RssHwmColumn,
LockedColumn,
SwapColumn,
VirtColumn,
TableConfiguration.GraphColumn, // Columns after this get graphed
RssColumn
},
Layout = TableLayoutStyle.GraphAndTable,
ChartType = ChartType.Line
};
rssConfig.AddColumnRole(ColumnRole.StartTime, StartTimestampColumn.Metadata.Guid);
rssConfig.AddColumnRole(ColumnRole.ResourceId, ProcessNameColumn);
rssConfig.AddColumnRole(ColumnRole.Duration, DurationColumn);
// rssHwm
var rssHwmConfig = new TableConfiguration("RSS Peak (high water mark)")
{
Columns = new[]
{
ProcessNameColumn,
TableConfiguration.PivotColumn, // Columns before this get pivotted on
StartTimestampColumn,
DurationColumn,
RssAnonColumn,
RssShMemColumn,
RssFileColumn,
RssColumn,
LockedColumn,
SwapColumn,
VirtColumn,
TableConfiguration.GraphColumn, // Columns after this get graphed
RssHwmColumn
},
Layout = TableLayoutStyle.GraphAndTable,
ChartType = ChartType.Line
};
rssHwmConfig.AddColumnRole(ColumnRole.StartTime, StartTimestampColumn.Metadata.Guid);
rssHwmConfig.AddColumnRole(ColumnRole.ResourceId, ProcessNameColumn);
rssHwmConfig.AddColumnRole(ColumnRole.Duration, DurationColumn);
// rssFile
var rssFileConfig = new TableConfiguration("RSS File")
{
Columns = new[]
{
ProcessNameColumn,
TableConfiguration.PivotColumn, // Columns before this get pivotted on
StartTimestampColumn,
DurationColumn,
RssAnonColumn,
RssShMemColumn,
RssHwmColumn,
RssColumn,
LockedColumn,
SwapColumn,
VirtColumn,
TableConfiguration.GraphColumn, // Columns after this get graphed
RssFileColumn
},
Layout = TableLayoutStyle.GraphAndTable,
ChartType = ChartType.Line
};
rssFileConfig.AddColumnRole(ColumnRole.StartTime, StartTimestampColumn.Metadata.Guid);
rssFileConfig.AddColumnRole(ColumnRole.ResourceId, ProcessNameColumn);
rssFileConfig.AddColumnRole(ColumnRole.Duration, DurationColumn);
// rssShMem
var rssShMemConfig = new TableConfiguration("RSS Shared Memory")
{
Columns = new[]
{
ProcessNameColumn,
TableConfiguration.PivotColumn, // Columns before this get pivotted on
StartTimestampColumn,
DurationColumn,
RssAnonColumn,
RssFileColumn,
RssHwmColumn,
RssColumn,
LockedColumn,
SwapColumn,
VirtColumn,
TableConfiguration.GraphColumn, // Columns after this get graphed
RssShMemColumn
},
Layout = TableLayoutStyle.GraphAndTable,
ChartType = ChartType.Line
};
rssShMemConfig.AddColumnRole(ColumnRole.StartTime, StartTimestampColumn.Metadata.Guid);
rssShMemConfig.AddColumnRole(ColumnRole.ResourceId, ProcessNameColumn);
rssShMemConfig.AddColumnRole(ColumnRole.Duration, DurationColumn);
// rssAnon
var rssAnonConfig = new TableConfiguration("RSS Anonymous")
{
Columns = new[]
{
ProcessNameColumn,
TableConfiguration.PivotColumn, // Columns before this get pivotted on
StartTimestampColumn,
DurationColumn,
RssShMemColumn,
RssFileColumn,
RssHwmColumn,
RssColumn,
LockedColumn,
SwapColumn,
VirtColumn,
TableConfiguration.GraphColumn, // Columns after this get graphed
RssAnonColumn
},
Layout = TableLayoutStyle.GraphAndTable,
ChartType = ChartType.Line
};
rssAnonConfig.AddColumnRole(ColumnRole.StartTime, StartTimestampColumn.Metadata.Guid);
rssAnonConfig.AddColumnRole(ColumnRole.ResourceId, ProcessNameColumn);
rssAnonConfig.AddColumnRole(ColumnRole.Duration, DurationColumn);
tableBuilder.AddTableConfiguration(virtConfig)
.AddTableConfiguration(virtConfig)
.AddTableConfiguration(swapConfig)
.AddTableConfiguration(lockedConfig)
.AddTableConfiguration(rssConfig)
.AddTableConfiguration(rssHwmConfig)
.AddTableConfiguration(rssFileConfig)
.AddTableConfiguration(rssShMemConfig)
.AddTableConfiguration(rssAnonConfig)
.SetDefaultTableConfiguration(virtConfig);
}
}
}

Просмотреть файл

@ -0,0 +1,78 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.Performance.SDK.Extensibility;
using Microsoft.Performance.SDK.Processing;
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Diagnostics.CodeAnalysis;
using PerfettoCds.Pipeline.DataOutput;
using Microsoft.Performance.SDK;
using PerfettoCds.Pipeline.CompositeDataCookers;
using System.Linq;
namespace PerfettoCds.Pipeline.Tables
{
[Table]
public class PerfettoSystemMemoryTable
{
public static TableDescriptor TableDescriptor => new TableDescriptor(
Guid.Parse("{edbd3ddd-5610-4929-a85f-f9ca6eceb9b2}"),
"Perfetto System Memory",
"Displays system memory counts gathered from /proc/meminfo",
"Perfetto - System",
requiredDataCookers: new List<DataCookerPath> { PerfettoPluginConstants.SystemMemoryEventCookerPath }
);
private static readonly ColumnConfiguration MemoryTypeColumn = new ColumnConfiguration(
new ColumnMetadata(new Guid("{ac84aa1d-ea66-46d2-8fc3-8ead853f81b4}"), "MemoryType", "Type of memory"),
new UIHints { Width = 210, });
private static readonly ColumnConfiguration MemoryValueColumn = new ColumnConfiguration(
new ColumnMetadata(new Guid("{3ada3dda-2893-4366-b1a7-a5fe8344e17b}"), "MemoryValue(kb)", "Memory value"),
new UIHints { Width = 210, AggregationMode = AggregationMode.Max});
private static readonly ColumnConfiguration StartTimestampColumn = new ColumnConfiguration(
new ColumnMetadata(new Guid("{6a9f870f-103c-461c-b909-9b098fe3695f}"), "StartTimestamp", "Start timestamp for the memory event"),
new UIHints { Width = 120 });
private static readonly ColumnConfiguration DurationColumn = new ColumnConfiguration(
new ColumnMetadata(new Guid("{bade2ff2-0a7c-4358-a736-058163739ae4}"), "Duration", "Start timestamp for the memory sample"),
new UIHints { Width = 120 });
public static void BuildTable(ITableBuilder tableBuilder, IDataExtensionRetrieval tableData)
{
// Get data from the cooker
var events = tableData.QueryOutput<ProcessedEventData<PerfettoSystemMemoryEvent>>(
new DataOutputPath(PerfettoPluginConstants.SystemMemoryEventCookerPath, nameof(PerfettoSystemMemoryEventCooker.SystemMemoryEvents)));
var tableGenerator = tableBuilder.SetRowCount((int)events.Count);
var baseProjection = Projection.Index(events);
tableGenerator.AddColumn(StartTimestampColumn, baseProjection.Compose(x => x.StartTimestamp));
tableGenerator.AddColumn(MemoryTypeColumn, baseProjection.Compose(x => x.MemoryType));
tableGenerator.AddColumn(MemoryValueColumn, baseProjection.Compose(x => x.Value));
tableGenerator.AddColumn(DurationColumn, baseProjection.Compose(x => x.Duration));
// Virtual
var tableConfig = new TableConfiguration("System Memory")
{
Columns = new[]
{
MemoryTypeColumn,
TableConfiguration.PivotColumn, // Columns before this get pivotted on
StartTimestampColumn,
DurationColumn,
TableConfiguration.GraphColumn, // Columns after this get graphed
MemoryValueColumn
},
Layout = TableLayoutStyle.GraphAndTable,
ChartType = ChartType.Line
};
tableConfig.AddColumnRole(ColumnRole.StartTime, StartTimestampColumn.Metadata.Guid);
tableConfig.AddColumnRole(ColumnRole.Duration, DurationColumn);
tableBuilder.AddTableConfiguration(tableConfig)
.SetDefaultTableConfiguration(tableConfig);
}
}
}

Просмотреть файл

@ -0,0 +1,65 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using Perfetto.Protos;
namespace PerfettoProcessor
{
public class PerfettoCounterTrackEvent : PerfettoSqlEvent
{
public const string Key = "PerfettoCounterTrackEvent";
public static string SqlQuery = "select id, name from counter_track";
public long Id { get; set; }
public string Name { get; set; }
public override string GetSqlQuery()
{
return SqlQuery;
}
public override string GetEventKey()
{
return Key;
}
public override void ProcessCell(string colName,
QueryResult.Types.CellsBatch.Types.CellType cellType,
QueryResult.Types.CellsBatch batch,
string[] stringCells,
CellCounters counters)
{
var col = colName.ToLower();
switch (cellType)
{
case Perfetto.Protos.QueryResult.Types.CellsBatch.Types.CellType.CellInvalid:
case Perfetto.Protos.QueryResult.Types.CellsBatch.Types.CellType.CellNull:
break;
case Perfetto.Protos.QueryResult.Types.CellsBatch.Types.CellType.CellVarint:
var longVal = batch.VarintCells[counters.IntCounter++];
switch (col)
{
case "id":
Id = longVal;
break;
}
break;
case Perfetto.Protos.QueryResult.Types.CellsBatch.Types.CellType.CellFloat64:
break;
case Perfetto.Protos.QueryResult.Types.CellsBatch.Types.CellType.CellString:
var strVal = stringCells[counters.StringCounter++];
switch (col)
{
case "name":
Name = strVal;
break;
}
break;
case Perfetto.Protos.QueryResult.Types.CellsBatch.Types.CellType.CellBlob:
break;
default:
throw new Exception("Unexpected CellType");
}
}
}
}

Просмотреть файл

@ -0,0 +1,69 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using Perfetto.Protos;
namespace PerfettoProcessor
{
public class PerfettoProcessCounterTrackEvent : PerfettoSqlEvent
{
public const string Key = "PerfettoProcessCounterTrackEvent";
public static string SqlQuery = "select name, id, upid from process_counter_track";
public long Id { get; set; }
public string Name { get; set; }
public long Upid { get; set; }
public override string GetSqlQuery()
{
return SqlQuery;
}
public override string GetEventKey()
{
return Key;
}
public override void ProcessCell(string colName,
QueryResult.Types.CellsBatch.Types.CellType cellType,
QueryResult.Types.CellsBatch batch,
string[] stringCells,
CellCounters counters)
{
var col = colName.ToLower();
switch (cellType)
{
case Perfetto.Protos.QueryResult.Types.CellsBatch.Types.CellType.CellInvalid:
case Perfetto.Protos.QueryResult.Types.CellsBatch.Types.CellType.CellNull:
break;
case Perfetto.Protos.QueryResult.Types.CellsBatch.Types.CellType.CellVarint:
var longVal = batch.VarintCells[counters.IntCounter++];
switch (col)
{
case "id":
Id = longVal;
break;
case "upid":
Upid = longVal;
break;
}
break;
case Perfetto.Protos.QueryResult.Types.CellsBatch.Types.CellType.CellFloat64:
break;
case Perfetto.Protos.QueryResult.Types.CellsBatch.Types.CellType.CellString:
var strVal = stringCells[counters.StringCounter++];
switch (col)
{
case "name":
Name = strVal;
break;
}
break;
case Perfetto.Protos.QueryResult.Types.CellsBatch.Types.CellType.CellBlob:
break;
default:
throw new Exception("Unexpected CellType");
}
}
}
}

Просмотреть файл

@ -282,6 +282,12 @@ namespace PerfettoProcessor
case PerfettoMetadataEvent.Key:
ev = new PerfettoMetadataEvent();
break;
case PerfettoProcessCounterTrackEvent.Key:
ev = new PerfettoProcessCounterTrackEvent();
break;
case PerfettoCounterTrackEvent.Key:
ev = new PerfettoCounterTrackEvent();
break;
default:
throw new Exception("Invalid event type");
}

Просмотреть файл

@ -3,7 +3,7 @@ using Microsoft.Performance.SDK.Processing;
using Microsoft.Performance.Toolkit.Engine;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PerfettoCds;
using PerfettoCds.Pipeline.DataCookers;
using PerfettoCds.Pipeline.CompositeDataCookers;
using PerfettoCds.Pipeline.DataOutput;
using System.IO;