/// <summary> /// Writes a profiling dataset to the database. /// </summary> public void WriteDataSet(IProfilingDataSet dataSet) { if (dataSet == null) throw new ArgumentNullException("dataSet"); using (SQLiteTransaction transaction = this.connection.BeginTransaction()) { SQLiteCommand cmd = this.connection.CreateCommand(); if (dataSetCount == -1) dataSetCount = 0; cmd.Parameters.Add(new SQLiteParameter("id", dataSetCount)); cmd.Parameters.Add(new SQLiteParameter("isfirst", dataSet.IsFirst)); cmd.Parameters.Add(new SQLiteParameter("rootid", functionInfoCount)); cmd.CommandText = "INSERT INTO DataSets(id, isfirst, rootid)" + "VALUES(?,?,?);"; int dataSetStartId = functionInfoCount; using (SQLiteCommand loopCommand = this.connection.CreateCommand()) { CallTreeNode node = dataSet.RootNode; loopCommand.CommandText = "INSERT INTO Calls(id, endid, parentid, nameid, cpucyclesspent, cpucyclesspentself, isactiveatstart, callcount)" + "VALUES(?,?,?,?,?,?,?,?);"; CallsParams dataParams = new CallsParams(); loopCommand.Parameters.Add(dataParams.functionInfoId = new SQLiteParameter()); loopCommand.Parameters.Add(dataParams.endId = new SQLiteParameter()); loopCommand.Parameters.Add(dataParams.parentId = new SQLiteParameter()); loopCommand.Parameters.Add(dataParams.nameId = new SQLiteParameter()); loopCommand.Parameters.Add(dataParams.cpuCyclesSpent = new SQLiteParameter()); loopCommand.Parameters.Add(dataParams.cpuCyclesSpentSelf = new SQLiteParameter()); loopCommand.Parameters.Add(dataParams.isActiveAtStart = new SQLiteParameter()); loopCommand.Parameters.Add(dataParams.callCount = new SQLiteParameter()); InsertCalls(loopCommand, node, -1, dataParams); } using (SQLiteCommand functionsCommand = this.connection.CreateCommand()) { functionsCommand.CommandText = string.Format(@" INSERT INTO Functions SELECT {0}, nameid, SUM(cpucyclesspent), SUM(cpucyclesspentself), SUM(isactiveatstart), SUM(callcount), MAX(id != endid) FROM Calls WHERE id BETWEEN {1} AND {2} GROUP BY nameid;", dataSetCount, dataSetStartId, functionInfoCount - 1); functionsCommand.ExecuteNonQuery(); } cmd.ExecuteNonQuery(); dataSetCount++; transaction.Commit(); } }
void InsertCalls(SQLiteCommand cmd, CallTreeNode node, int parentId, CallsParams dataParams) { int thisID = functionInfoCount++; foreach (CallTreeNode child in node.Children) { InsertCalls(cmd, child, thisID, dataParams); } long cpuCycles = node.CpuCyclesSpent; long cpuCyclesSelf = node.CpuCyclesSpentSelf; // we sometimes saw invalid data with the 0x0080000000000000L bit set if (cpuCycles > 0x0007ffffffffffffL || cpuCycles < 0) { throw new InvalidOperationException("Too large CpuCyclesSpent - there's something wrong in the data"); } if (node.NameMapping.Id != 0 && (cpuCyclesSelf > cpuCycles || cpuCyclesSelf < 0)) { throw new InvalidOperationException("Too large/small CpuCyclesSpentSelf (" + cpuCyclesSelf + ") - there's something wrong in the data"); } dataParams.callCount.Value = node.RawCallCount; dataParams.isActiveAtStart.Value = node.IsActiveAtStart; dataParams.cpuCyclesSpent.Value = cpuCycles; dataParams.cpuCyclesSpentSelf.Value = cpuCyclesSelf; dataParams.functionInfoId.Value = thisID; dataParams.nameId.Value = node.NameMapping.Id; dataParams.parentId.Value = parentId; dataParams.endId.Value = functionInfoCount - 1; cmd.ExecuteNonQuery(); }