Browse Source

added basic support for event data collected by Hook.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@5195 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Siegfried Pammer 17 years ago
parent
commit
bc817ae3e0
  1. 7
      src/AddIns/Misc/Profiler/Controller/Data/IProfilingDataWriter.cs
  2. 30
      src/AddIns/Misc/Profiler/Controller/Data/PerformanceCounterDescriptor.cs
  3. 2
      src/AddIns/Misc/Profiler/Controller/Data/ProfilingDataProvider.cs
  4. 24
      src/AddIns/Misc/Profiler/Controller/Data/ProfilingDataSQLiteProvider.cs
  5. 62
      src/AddIns/Misc/Profiler/Controller/Data/ProfilingDataSQLiteWriter.cs
  6. 16
      src/AddIns/Misc/Profiler/Controller/Data/TempFileDatabase.cs
  7. 16
      src/AddIns/Misc/Profiler/Controller/Data/UnitTestRootCallTreeNode.cs
  8. 13
      src/AddIns/Misc/Profiler/Controller/Data/UnitTestWriter.cs
  9. 18
      src/AddIns/Misc/Profiler/Controller/Data/UnmanagedCallTreeNode.cs
  10. 1
      src/AddIns/Misc/Profiler/Controller/Profiler.Controller.csproj
  11. 15
      src/AddIns/Misc/Profiler/Controller/Profiler.cs
  12. 4
      src/AddIns/Misc/Profiler/Controller/ProfilerOptions.cs

7
src/AddIns/Misc/Profiler/Controller/Data/IProfilingDataWriter.cs

@ -31,6 +31,8 @@ namespace ICSharpCode.Profiler.Controller.Data
void WritePerformanceCounterData(IEnumerable<PerformanceCounterDescriptor> counters); void WritePerformanceCounterData(IEnumerable<PerformanceCounterDescriptor> counters);
void WriteEventData(IEnumerable<EventDataEntry> events);
/// <summary> /// <summary>
/// Closes and disposes the underlying data structure. /// Closes and disposes the underlying data structure.
/// </summary> /// </summary>
@ -41,5 +43,10 @@ namespace ICSharpCode.Profiler.Controller.Data
/// The processor frequency is measured in MHz. /// The processor frequency is measured in MHz.
/// </summary> /// </summary>
int ProcessorFrequency { get; set; } int ProcessorFrequency { get; set; }
/// <summary>
/// Gets the number of datasets that have been written by this IProfilingDataWriter.
/// </summary>
int DataSetCount { get; }
} }
} }

30
src/AddIns/Misc/Profiler/Controller/Data/PerformanceCounterDescriptor.cs

@ -23,12 +23,13 @@ namespace ICSharpCode.Profiler.Controller.Data
public float? MinValue { get; private set; } public float? MinValue { get; private set; }
public float? MaxValue { get; private set; } public float? MaxValue { get; private set; }
public string Unit { get; private set; } public string Unit { get; private set; }
public string Format { get; private set; }
float defaultValue; float defaultValue;
PerformanceCounter counter; PerformanceCounter counter;
public PerformanceCounterDescriptor(string category, string name, string instance, string computer, public PerformanceCounterDescriptor(string category, string name, string instance, string computer,
float defaultValue, float? minValue, float? maxValue, string unit) float defaultValue, float? minValue, float? maxValue, string unit, string format)
{ {
Category = category; Category = category;
Name = name; Name = name;
@ -39,10 +40,11 @@ namespace ICSharpCode.Profiler.Controller.Data
MinValue = minValue; MinValue = minValue;
MaxValue = maxValue; MaxValue = maxValue;
Unit = unit; Unit = unit;
Format = format;
} }
public PerformanceCounterDescriptor(string name, float? minValue, float? maxValue, string unit) public PerformanceCounterDescriptor(string name, float? minValue, float? maxValue, string unit, string format)
: this(null, name, null, null, 0, minValue, maxValue, unit) : this(null, name, null, null, 0, minValue, maxValue, unit, format)
{ {
} }
@ -52,8 +54,8 @@ namespace ICSharpCode.Profiler.Controller.Data
string[] instances = cat.GetInstanceNames(); string[] instances = cat.GetInstanceNames();
foreach (string instance in instances) { foreach (string instance in instances) {
using (PerformanceCounter cnt = new PerformanceCounter("Process", "ID Process", instance, true)) { using (PerformanceCounter procIdCounter = new PerformanceCounter("Process", "ID Process", instance, true)) {
int val = (int)cnt.RawValue; int val = (int)procIdCounter.RawValue;
if (val == pid) if (val == pid)
return instance; return instance;
} }
@ -75,7 +77,9 @@ namespace ICSharpCode.Profiler.Controller.Data
try { try {
this.Values.Add(counter.NextValue()); this.Values.Add(counter.NextValue());
} catch (Exception e) { } catch (Exception e) {
#if DEBUG
Console.WriteLine(e.ToString()); Console.WriteLine(e.ToString());
#endif
this.Values.Add(defaultValue); this.Values.Add(defaultValue);
} }
} }
@ -85,4 +89,20 @@ namespace ICSharpCode.Profiler.Controller.Data
return Name; return Name;
} }
} }
public enum EventType : int
{
Exception = 0,
Console = 1,
WindowsForms = 2,
WindowsPresentationFoundation = 3
}
public class EventDataEntry
{
public int DataSetId { get; set; }
public EventType Type { get; set; }
public int NameId { get; set; }
public string Data { get; set; }
}
} }

2
src/AddIns/Misc/Profiler/Controller/Data/ProfilingDataProvider.cs

@ -80,5 +80,7 @@ namespace ICSharpCode.Profiler.Controller.Data
public abstract PerformanceCounterDescriptor[] GetPerformanceCounters(); public abstract PerformanceCounterDescriptor[] GetPerformanceCounters();
public abstract float[] GetPerformanceCounterValues(int index); public abstract float[] GetPerformanceCounterValues(int index);
public abstract EventDataEntry[] GetEventDataEntries(int index);
} }
} }

24
src/AddIns/Misc/Profiler/Controller/Data/ProfilingDataSQLiteProvider.cs

@ -356,7 +356,7 @@ namespace ICSharpCode.Profiler.Controller.Data
{ {
SQLiteCommand cmd; SQLiteCommand cmd;
using (LockAndCreateCommand(out cmd)) { using (LockAndCreateCommand(out cmd)) {
cmd.CommandText = "SELECT name, minvalue, maxvalue, unit " + cmd.CommandText = "SELECT name, minvalue, maxvalue, unit, format " +
"FROM PerformanceCounter " + "FROM PerformanceCounter " +
"ORDER BY id ASC;"; "ORDER BY id ASC;";
@ -370,7 +370,8 @@ namespace ICSharpCode.Profiler.Controller.Data
reader.GetString(0), reader.GetString(0),
reader.IsDBNull(1) ? null : new Nullable<float>(reader.GetFloat(1)), reader.IsDBNull(1) ? null : new Nullable<float>(reader.GetFloat(1)),
reader.IsDBNull(2) ? null : new Nullable<float>(reader.GetFloat(2)), reader.IsDBNull(2) ? null : new Nullable<float>(reader.GetFloat(2)),
reader.GetString(3) reader.GetString(3),
reader.GetString(4)
) )
); );
} }
@ -399,6 +400,25 @@ namespace ICSharpCode.Profiler.Controller.Data
} }
} }
public override EventDataEntry[] GetEventDataEntries(int index)
{
SQLiteCommand cmd;
using (LockAndCreateCommand(out cmd)) {
cmd.CommandText = "SELECT eventtype, nameid, data " +
"FROM EventData " +
"WHERE datasetid = " + index;
List<EventDataEntry> list = new List<EventDataEntry>();
var reader = cmd.ExecuteReader();
while (reader.Read())
list.Add(new EventDataEntry() { Data = reader.GetString(2), DataSetId = index, NameId = reader.GetInt32(1), Type = (EventType)reader.GetInt32(0) });
return list.ToArray();
}
}
Expression<Func<SingleCall, bool>> DataSetFilter(int startIndex, int endIndex) Expression<Func<SingleCall, bool>> DataSetFilter(int startIndex, int endIndex)
{ {
return c => startIndex <= c.DataSetID && c.DataSetID <= endIndex; return c => startIndex <= c.DataSetID && c.DataSetID <= endIndex;

62
src/AddIns/Misc/Profiler/Controller/Data/ProfilingDataSQLiteWriter.cs

@ -61,6 +61,9 @@ namespace ICSharpCode.Profiler.Controller.Data
/// </summary> /// </summary>
public void Close() public void Close()
{ {
if (isDisposed)
return;
using (SQLiteCommand cmd = this.connection.CreateCommand()) { using (SQLiteCommand cmd = this.connection.CreateCommand()) {
// create index at the end (after inserting data), this is faster // create index at the end (after inserting data), this is faster
cmd.CommandText = CallsAndFunctionsIndexDefs; cmd.CommandText = CallsAndFunctionsIndexDefs;
@ -170,6 +173,7 @@ namespace ICSharpCode.Profiler.Controller.Data
name TEXT NOT NULL, name TEXT NOT NULL,
minvalue REAL NULL, minvalue REAL NULL,
maxvalue REAL NULL, maxvalue REAL NULL,
format TEXT NOT NULL,
unit TEXT NOT NULL unit TEXT NOT NULL
); );
@ -178,6 +182,13 @@ namespace ICSharpCode.Profiler.Controller.Data
counterid INTEGER NOT NULL, counterid INTEGER NOT NULL,
value REAL NOT NULL value REAL NOT NULL
); );
CREATE TABLE EventData(
datasetid INTEGER NOT NULL,
eventtype INTEGER NOT NULL,
nameid INTEGER NOT NULL,
data TEXT NULL
);
"; ";
internal const string CallsAndFunctionsIndexDefs = internal const string CallsAndFunctionsIndexDefs =
@ -239,19 +250,22 @@ namespace ICSharpCode.Profiler.Controller.Data
InsertCalls(cmd, child, thisID, dataParams); InsertCalls(cmd, child, thisID, dataParams);
} }
long cpuCycles = node.CpuCyclesSpent;
long cpuCyclesSelf = node.CpuCyclesSpentSelf;
// we sometimes saw invalid data with the 0x0080000000000000L bit set // we sometimes saw invalid data with the 0x0080000000000000L bit set
if (node.CpuCyclesSpent > 0x0007ffffffffffffL || node.CpuCyclesSpent < 0) { if (cpuCycles > 0x0007ffffffffffffL || cpuCycles < 0) {
throw new InvalidOperationException("Too large CpuCyclesSpent - there's something wrong in the data"); throw new InvalidOperationException("Too large CpuCyclesSpent - there's something wrong in the data");
} }
if (node.NameMapping.Id != 0 && (node.CpuCyclesSpentSelf > node.CpuCyclesSpent || node.CpuCyclesSpentSelf < 0)) { if (node.NameMapping.Id != 0 && (cpuCyclesSelf > cpuCycles || cpuCyclesSelf < 0)) {
throw new InvalidOperationException("Too large/small CpuCyclesSpentSelf (" + node.CpuCyclesSpentSelf + ") - there's something wrong in the data"); throw new InvalidOperationException("Too large/small CpuCyclesSpentSelf (" + cpuCyclesSelf + ") - there's something wrong in the data");
} }
dataParams.callCount.Value = node.RawCallCount; dataParams.callCount.Value = node.RawCallCount;
dataParams.isActiveAtStart.Value = node.IsActiveAtStart; dataParams.isActiveAtStart.Value = node.IsActiveAtStart;
dataParams.cpuCyclesSpent.Value = node.CpuCyclesSpent; dataParams.cpuCyclesSpent.Value = cpuCycles;
dataParams.cpuCyclesSpentSelf.Value = node.CpuCyclesSpentSelf; dataParams.cpuCyclesSpentSelf.Value = cpuCyclesSelf;
dataParams.functionInfoId.Value = thisID; dataParams.functionInfoId.Value = thisID;
dataParams.nameId.Value = node.NameMapping.Id; dataParams.nameId.Value = node.NameMapping.Id;
@ -302,6 +316,7 @@ namespace ICSharpCode.Profiler.Controller.Data
isDisposed = true; isDisposed = true;
} }
/// <inheritdoc/>
public void WritePerformanceCounterData(IEnumerable<PerformanceCounterDescriptor> counters) public void WritePerformanceCounterData(IEnumerable<PerformanceCounterDescriptor> counters)
{ {
using (SQLiteTransaction trans = this.connection.BeginTransaction()) { using (SQLiteTransaction trans = this.connection.BeginTransaction()) {
@ -316,8 +331,8 @@ namespace ICSharpCode.Profiler.Controller.Data
SQLiteParameter unitParam = new SQLiteParameter("unit"); SQLiteParameter unitParam = new SQLiteParameter("unit");
cmd.CommandText = cmd.CommandText =
"INSERT OR IGNORE INTO PerformanceCounter(id, name, minvalue, maxvalue, unit)" + "INSERT OR IGNORE INTO PerformanceCounter(id, name, minvalue, maxvalue, unit)" + // should I split these queries
"VALUES(@id,@name,@min,@max,@unit);" + "VALUES(@id,@name,@min,@max,@unit);" + // for better performance?
"INSERT INTO CounterData(datasetid, counterid, value)" + "INSERT INTO CounterData(datasetid, counterid, value)" +
"VALUES(@dataset,@id,@value);"; "VALUES(@dataset,@id,@value);";
@ -344,5 +359,38 @@ namespace ICSharpCode.Profiler.Controller.Data
trans.Commit(); trans.Commit();
} }
} }
/// <inheritdoc/>
public void WriteEventData(IEnumerable<EventDataEntry> events)
{
using (SQLiteTransaction trans = this.connection.BeginTransaction()) {
using (SQLiteCommand cmd = this.connection.CreateCommand()) {
SQLiteParameter dataSetParam = new SQLiteParameter("datasetid");
SQLiteParameter eventTypeParam = new SQLiteParameter("eventtype");
SQLiteParameter nameIdParam = new SQLiteParameter("nameid");
SQLiteParameter dataParam = new SQLiteParameter("data");
cmd.CommandText =
"INSERT INTO EventData(datasetid,eventtype,nameid,data) " +
"VALUES(@datasetid,@eventtype,@nameid,@data);";
cmd.Parameters.AddRange(new SQLiteParameter[] { dataSetParam, eventTypeParam, nameIdParam, dataParam });
foreach (EventDataEntry entry in events) {
dataSetParam.Value = entry.DataSetId;
eventTypeParam.Value = (int)entry.Type;
nameIdParam.Value = entry.NameId;
dataParam.Value = entry.Data;
cmd.ExecuteNonQuery();
}
}
trans.Commit();
}
}
/// <inheritdoc/>
public int DataSetCount {
get { return this.dataSetCount; }
}
} }
} }

16
src/AddIns/Misc/Profiler/Controller/Data/TempFileDatabase.cs

@ -43,6 +43,12 @@ namespace ICSharpCode.Profiler.Controller.Data
get { return counters.AsReadOnly(); } get { return counters.AsReadOnly(); }
} }
List<EventDataEntry> events = new List<EventDataEntry>();
public ReadOnlyCollection<EventDataEntry> Events {
get { return events.AsReadOnly(); }
}
struct StreamInfo struct StreamInfo
{ {
public TargetProcessPointer NativeStartPosition { get; set; } public TargetProcessPointer NativeStartPosition { get; set; }
@ -143,6 +149,15 @@ namespace ICSharpCode.Profiler.Controller.Data
{ {
this.database.counters.AddRange(counters); this.database.counters.AddRange(counters);
} }
public void WriteEventData(IEnumerable<EventDataEntry> events)
{
this.database.events.AddRange(events);
}
public int DataSetCount {
get { return this.database.DataSetCount; }
}
} }
#endregion #endregion
@ -229,6 +244,7 @@ namespace ICSharpCode.Profiler.Controller.Data
writer.ProcessorFrequency = this.processorFrequency; writer.ProcessorFrequency = this.processorFrequency;
writer.WriteMappings(this.nameMappings.Values); writer.WriteMappings(this.nameMappings.Values);
writer.WritePerformanceCounterData(this.counters); writer.WritePerformanceCounterData(this.counters);
writer.WriteEventData(this.events);
for (int i = 0; i < this.DataSetCount; i++) { for (int i = 0; i < this.DataSetCount; i++) {
using (UnmanagedProfilingDataSet dataSet = this.LoadDataSet(i)) using (UnmanagedProfilingDataSet dataSet = this.LoadDataSet(i))

16
src/AddIns/Misc/Profiler/Controller/Data/UnitTestRootCallTreeNode.cs

@ -15,13 +15,14 @@ namespace ICSharpCode.Profiler.Controller.Data
/// </summary> /// </summary>
public class UnitTestRootCallTreeNode : CallTreeNode public class UnitTestRootCallTreeNode : CallTreeNode
{ {
List<CallTreeNode> unitTests; List<CallTreeNode> unitTests = null;
/// <summary> /// <summary>
/// Creates a new UnitTestRootCallTreeNode. /// Creates a new UnitTestRootCallTreeNode.
/// </summary> /// </summary>
public UnitTestRootCallTreeNode(IEnumerable<CallTreeNode> unitTests) public UnitTestRootCallTreeNode(IEnumerable<CallTreeNode> unitTests)
{ {
if (unitTests != null)
this.unitTests = new List<CallTreeNode>(unitTests); this.unitTests = new List<CallTreeNode>(unitTests);
} }
@ -42,7 +43,7 @@ namespace ICSharpCode.Profiler.Controller.Data
/// <inheritdoc/> /// <inheritdoc/>
public override bool IsActiveAtStart { public override bool IsActiveAtStart {
get { get {
return this.unitTests.Any(test => test.IsActiveAtStart); return (this.unitTests == null) ? false : this.unitTests.Any(test => test.IsActiveAtStart);
} }
} }
@ -77,14 +78,19 @@ namespace ICSharpCode.Profiler.Controller.Data
/// <inheritdoc/> /// <inheritdoc/>
public override int GetHashCode() public override int GetHashCode()
{ {
return this.unitTests.Aggregate(0, (sum, item) => sum ^= item.GetHashCode()); return (this.unitTests == null) ? 0 : this.unitTests.Aggregate(0, (sum, item) => sum ^= item.GetHashCode());
} }
/// <inheritdoc/> /// <inheritdoc/>
public override bool Equals(CallTreeNode other) public override bool Equals(CallTreeNode other)
{ {
UnitTestRootCallTreeNode node = other as UnitTestRootCallTreeNode; UnitTestRootCallTreeNode node = other as UnitTestRootCallTreeNode;
return node != null && node.unitTests.SequenceEqual(unitTests);
if (node != null && unitTests != null) {
return node.unitTests.SequenceEqual(unitTests);
}
return false;
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -97,7 +103,7 @@ namespace ICSharpCode.Profiler.Controller.Data
/// <inheritdoc/> /// <inheritdoc/>
public override IQueryable<CallTreeNode> Children { public override IQueryable<CallTreeNode> Children {
get { get {
return unitTests.AsQueryable(); return ((unitTests == null) ? Enumerable.Empty<CallTreeNode>() : unitTests).AsQueryable();
} }
} }

13
src/AddIns/Misc/Profiler/Controller/Data/UnitTestWriter.cs

@ -69,6 +69,10 @@ namespace ICSharpCode.Profiler.Controller.Data
this.targetWriter.WriteDataSet( this.targetWriter.WriteDataSet(
new UnitTestDataSet(new UnitTestRootCallTreeNode(list), dataSet.IsFirst) new UnitTestDataSet(new UnitTestRootCallTreeNode(list), dataSet.IsFirst)
); );
} else {
this.targetWriter.WriteDataSet(
new UnitTestDataSet(new UnitTestRootCallTreeNode(null), dataSet.IsFirst)
);
} }
} }
@ -105,5 +109,14 @@ namespace ICSharpCode.Profiler.Controller.Data
{ {
this.targetWriter.WritePerformanceCounterData(counters); this.targetWriter.WritePerformanceCounterData(counters);
} }
public void WriteEventData(IEnumerable<EventDataEntry> events)
{
this.targetWriter.WriteEventData(events);
}
public int DataSetCount {
get { return this.targetWriter.DataSetCount; }
}
} }
} }

18
src/AddIns/Misc/Profiler/Controller/Data/UnmanagedCallTreeNode.cs

@ -83,6 +83,24 @@ namespace ICSharpCode.Profiler.Controller.Data
} }
} }
public override long CpuCyclesSpentSelf {
get {
dataSet.VerifyAccess();
long result = (long)(this.data->TimeSpent & CpuCycleMask);
TargetProcessPointer32* childrenPtr = FunctionInfo.GetChildren32(data);
for (int i = 0; i <= data->LastChildIndex; i++)
{
FunctionInfo* child = dataSet.GetFunctionInfo(childrenPtr[i]);
if (child != null)
result -= (long)(child->TimeSpent & CpuCycleMask);
}
return result;
}
}
public override CallTreeNode Parent { public override CallTreeNode Parent {
get { get {
return this.parent; return this.parent;

1
src/AddIns/Misc/Profiler/Controller/Profiler.Controller.csproj

@ -89,7 +89,6 @@
<Reference Include="System.Data" /> <Reference Include="System.Data" />
<Reference Include="System.Data.SQLite"> <Reference Include="System.Data.SQLite">
<HintPath>..\..\..\..\Libraries\SQLite\System.Data.SQLite.dll</HintPath> <HintPath>..\..\..\..\Libraries\SQLite\System.Data.SQLite.dll</HintPath>
<Private>True</Private>
</Reference> </Reference>
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>

15
src/AddIns/Misc/Profiler/Controller/Profiler.cs

@ -619,7 +619,6 @@ namespace ICSharpCode.Profiler.Controller
isRunning = false; isRunning = false;
this.dataWriter.WritePerformanceCounterData(performanceCounters); this.dataWriter.WritePerformanceCounterData(performanceCounters);
this.dataWriter.Close(); this.dataWriter.Close();
OnSessionEnded(EventArgs.Empty); OnSessionEnded(EventArgs.Empty);
@ -703,10 +702,22 @@ namespace ICSharpCode.Profiler.Controller
string name = parts[3] + ((string.IsNullOrEmpty(parts[4])) ? "" : " - " + parts[4]); string name = parts[3] + ((string.IsNullOrEmpty(parts[4])) ? "" : " - " + parts[4]);
lock (this.dataWriter) { lock (this.dataWriter) {
this.dataWriter.WriteMappings(new NameMapping[] {new NameMapping(id, null, name, null)}); this.dataWriter.WriteMappings(new[] {new NameMapping(id, null, name, null)});
} }
return true; return true;
} else if (readString.StartsWith("event ", StringComparison.Ordinal)) {
string[] parts = readString.Split(' ');
// event <typeid> <nameid> <data>
if (parts.Length != 4)
return false;
int type = int.Parse(parts[1], CultureInfo.InvariantCulture);
int name = int.Parse(parts[2], CultureInfo.InvariantCulture);
string data = parts[3];
lock (this.dataWriter) {
this.dataWriter.WriteEventData(new[] { new EventDataEntry() { DataSetId = this.dataWriter.DataSetCount, NameId = name, Type = (EventType)type, Data = data } });
}
} else { } else {
if (readString.StartsWith("error-", StringComparison.Ordinal)) { if (readString.StartsWith("error-", StringComparison.Ordinal)) {
string[] parts = readString.Split('-'); string[] parts = readString.Split('-');

4
src/AddIns/Misc/Profiler/Controller/ProfilerOptions.cs

@ -25,8 +25,8 @@ namespace ICSharpCode.Profiler.Controller
public const int DefaultSharedMemorySize = 64 * 1024 * 1024; // 64 mb public const int DefaultSharedMemorySize = 64 * 1024 * 1024; // 64 mb
public static readonly PerformanceCounterDescriptor[] DefaultCounters = new[] { public static readonly PerformanceCounterDescriptor[] DefaultCounters = new[] {
new PerformanceCounterDescriptor("Process", "% Processor Time", "_Total", ".", 0, 0, 100, "%"), new PerformanceCounterDescriptor("Process", "% Processor Time", "_Total", ".", 0, 0, 100, "%", "0.00"),
new PerformanceCounterDescriptor("Process", "IO Data Bytes/sec", "_Total", ".", 0, null, null, "bytes/sec") new PerformanceCounterDescriptor("Process", "IO Data Bytes/sec", "_Total", ".", 0, null, null, "bytes/sec", "#,##0")
}; };
bool enableDC; bool enableDC;

Loading…
Cancel
Save