diff --git a/src/AddIns/Misc/Profiler/Controller/Data/ProfilingDataSQLiteProvider.cs b/src/AddIns/Misc/Profiler/Controller/Data/ProfilingDataSQLiteProvider.cs index 52a552c196..c81604ff34 100644 --- a/src/AddIns/Misc/Profiler/Controller/Data/ProfilingDataSQLiteProvider.cs +++ b/src/AddIns/Misc/Profiler/Controller/Data/ProfilingDataSQLiteProvider.cs @@ -34,7 +34,7 @@ namespace ICSharpCode.Profiler.Controller.Data /// /// Creates a new SQLite profiling data provider and opens a database stored in a file. /// - private ProfilingDataSQLiteProvider(string fileName, bool allowUpgrade) + ProfilingDataSQLiteProvider(string fileName, bool allowUpgrade) { this.nameMappingCache = new Dictionary(); diff --git a/src/AddIns/Misc/Profiler/Controller/Data/ProfilingDataSQLiteWriter.cs b/src/AddIns/Misc/Profiler/Controller/Data/ProfilingDataSQLiteWriter.cs index ef5aed0259..28167133ee 100644 --- a/src/AddIns/Misc/Profiler/Controller/Data/ProfilingDataSQLiteWriter.cs +++ b/src/AddIns/Misc/Profiler/Controller/Data/ProfilingDataSQLiteWriter.cs @@ -321,39 +321,48 @@ namespace ICSharpCode.Profiler.Controller.Data { using (SQLiteTransaction trans = this.connection.BeginTransaction()) { using (SQLiteCommand cmd = this.connection.CreateCommand()) { + using (SQLiteCommand cmd2 = this.connection.CreateCommand()) { - SQLiteParameter idParam = new SQLiteParameter("id"); - SQLiteParameter nameParam = new SQLiteParameter("name"); - SQLiteParameter dataSetParam = new SQLiteParameter("dataset"); - SQLiteParameter valueParam = new SQLiteParameter("value"); - SQLiteParameter minParam = new SQLiteParameter("min"); - SQLiteParameter maxParam = new SQLiteParameter("max"); - SQLiteParameter unitParam = new SQLiteParameter("unit"); - - cmd.CommandText = - "INSERT OR IGNORE INTO PerformanceCounter(id, name, minvalue, maxvalue, unit)" + // should I split these queries - "VALUES(@id,@name,@min,@max,@unit);" + // for better performance? - "INSERT INTO CounterData(datasetid, counterid, value)" + - "VALUES(@dataset,@id,@value);"; - - cmd.Parameters.AddRange(new SQLiteParameter[] { idParam, nameParam, dataSetParam, valueParam, minParam, maxParam, unitParam }); - - int id = 0; - - foreach (PerformanceCounterDescriptor counter in counters) { - idParam.Value = id; - nameParam.Value = counter.Name; - minParam.Value = counter.MinValue; - maxParam.Value = counter.MaxValue; - unitParam.Value = counter.Unit; + SQLiteParameter idParam = new SQLiteParameter("id"); + SQLiteParameter nameParam = new SQLiteParameter("name"); + SQLiteParameter dataSetParam = new SQLiteParameter("dataset"); + SQLiteParameter valueParam = new SQLiteParameter("value"); + SQLiteParameter minParam = new SQLiteParameter("min"); + SQLiteParameter maxParam = new SQLiteParameter("max"); + SQLiteParameter unitParam = new SQLiteParameter("unit"); + SQLiteParameter formatParam = new SQLiteParameter("format"); - for (int i = 0; i < counter.Values.Count; i++) { - dataSetParam.Value = i; - valueParam.Value = counter.Values[i]; - cmd.ExecuteNonQuery(); - } + cmd.Parameters.AddRange(new SQLiteParameter[] { idParam, dataSetParam, valueParam }); + cmd2.Parameters.AddRange(new SQLiteParameter[] { idParam, nameParam, minParam, maxParam, unitParam, formatParam }); + + cmd2.CommandText = + "INSERT INTO PerformanceCounter(id, name, minvalue, maxvalue, unit, format)" + + "VALUES(@id,@name,@min,@max,@unit,@format);"; - id++; + cmd.CommandText = + "INSERT INTO CounterData(datasetid, counterid, value)" + + "VALUES(@dataset,@id,@value);"; + + int id = 0; + + foreach (PerformanceCounterDescriptor counter in counters) { + idParam.Value = id; + nameParam.Value = counter.Name; + minParam.Value = counter.MinValue; + maxParam.Value = counter.MaxValue; + unitParam.Value = counter.Unit; + formatParam.Value = counter.Format; + + for (int i = 0; i < counter.Values.Count; i++) { + dataSetParam.Value = i; + valueParam.Value = counter.Values[i]; + cmd.ExecuteNonQuery(); + } + + cmd2.ExecuteNonQuery(); + + id++; + } } } trans.Commit(); diff --git a/src/AddIns/Misc/Profiler/Controller/Profiler.cs b/src/AddIns/Misc/Profiler/Controller/Profiler.cs index 0eb800ac34..b24f532749 100644 --- a/src/AddIns/Misc/Profiler/Controller/Profiler.cs +++ b/src/AddIns/Misc/Profiler/Controller/Profiler.cs @@ -707,9 +707,9 @@ namespace ICSharpCode.Profiler.Controller return true; } else if (readString.StartsWith("event ", StringComparison.Ordinal)) { - string[] parts = readString.Split(' '); + IList parts = readString.SplitSeparatedString(' '); // event - if (parts.Length != 4) + if (parts.Count != 4) return false; int type = int.Parse(parts[1], CultureInfo.InvariantCulture); int name = int.Parse(parts[2], CultureInfo.InvariantCulture); @@ -718,6 +718,7 @@ namespace ICSharpCode.Profiler.Controller lock (this.dataWriter) { this.dataWriter.WriteEventData(new[] { new EventDataEntry() { DataSetId = this.dataWriter.DataSetCount, NameId = name, Type = (EventType)type, Data = data } }); } + return true; } else { if (readString.StartsWith("error-", StringComparison.Ordinal)) { string[] parts = readString.Split('-'); diff --git a/src/AddIns/Misc/Profiler/Controller/structs.cs b/src/AddIns/Misc/Profiler/Controller/structs.cs index 393319f186..b8e2805656 100644 --- a/src/AddIns/Misc/Profiler/Controller/structs.cs +++ b/src/AddIns/Misc/Profiler/Controller/structs.cs @@ -221,6 +221,7 @@ namespace ICSharpCode.Profiler.Controller { public int ThreadID; public volatile int InLock; + public volatile bool Active; public TargetProcessPointer32 Predecessor; public TargetProcessPointer32 Follower; public LightweightStack32 Stack; diff --git a/src/AddIns/Misc/Profiler/Hook/LightweightList.cpp b/src/AddIns/Misc/Profiler/Hook/LightweightList.cpp index eb578e69b5..1348cc9972 100644 --- a/src/AddIns/Misc/Profiler/Hook/LightweightList.cpp +++ b/src/AddIns/Misc/Profiler/Hook/LightweightList.cpp @@ -23,6 +23,8 @@ ThreadLocalData *LightweightList::add() void *itemMemory = stackAllocator.malloc(sizeof(ThreadLocalData)); assert(itemMemory != nullptr); ThreadLocalData *item = new (itemMemory) ThreadLocalData(); + + item->active = true; if (this->lastItem == nullptr) { this->lastItem = item; diff --git a/src/AddIns/Misc/Profiler/Hook/Profiler.cpp b/src/AddIns/Misc/Profiler/Hook/Profiler.cpp index f7dcf66f4d..82cc8c479b 100644 --- a/src/AddIns/Misc/Profiler/Hook/Profiler.cpp +++ b/src/AddIns/Misc/Profiler/Hook/Profiler.cpp @@ -77,6 +77,9 @@ ASSEMBLER_CALLBACK FunctionEnterGlobal(int functionID) FunctionEnterCreateNewRoot(data, __rdtsc()); } else profiler.EnterLock(data); + + if (!data->active) + goto EXIT; // this call allows GetOrAddChild to update the value at the top of the stack // if the FunctionInfo is resized @@ -109,7 +112,7 @@ ASSEMBLER_CALLBACK FunctionEnterGlobal(int functionID) data->stack.push(StackEntry(child, __rdtsc())); } - +EXIT: data->inLock = 0; } @@ -131,6 +134,9 @@ ASSEMBLER_CALLBACK FunctionLeaveGlobal() ThreadLocalData *data = getThreadLocalData(); profiler.EnterLock(data); + + if (!data->active) + goto EXIT; if (data->stack.empty()) { //DebugWriteLine(L"FunctionLeaveGlobal (but stack was empty)"); @@ -143,7 +149,8 @@ ASSEMBLER_CALLBACK FunctionLeaveGlobal() data->stack.pop(); } } - + +EXIT: data->inLock = 0; } @@ -238,7 +245,6 @@ CProfiler::CProfiler() this->pICorProfilerInfo = nullptr; this->pICorProfilerInfo2 = nullptr; this->sigReader = nullptr; - this->active = true; } // ---- ICorProfilerCallback IMPLEMENTATION ------------------ @@ -626,12 +632,14 @@ STDMETHODIMP CProfiler::JITCompilationStarted(FunctionID functionID, BOOL /*fIsS void CProfiler::Activate() { - + ThreadLocalData *data = getThreadLocalData(); + data->active = true; } void CProfiler::Deactivate() { - + ThreadLocalData *data = getThreadLocalData(); + data->active = false; } const ULONG FAT_HEADER_SIZE = 0xC; /* 12 bytes = WORD + WORD + DWORD + DWORD */ diff --git a/src/AddIns/Misc/Profiler/Hook/Profiler.h b/src/AddIns/Misc/Profiler/Hook/Profiler.h index 58e873f5c4..92f6ee62ef 100644 --- a/src/AddIns/Misc/Profiler/Hook/Profiler.h +++ b/src/AddIns/Misc/Profiler/Hook/Profiler.h @@ -132,8 +132,6 @@ private: TUThreadIDMap unmanagedThreadIDMap; TMethodTokenMap methodMap; - bool active; - // function to set up our event mask HRESULT SetEventMask(); void Rewrite(FunctionID functionID, int type, int nameId, WCHAR *name); diff --git a/src/AddIns/Misc/Profiler/Hook/constants.cpp b/src/AddIns/Misc/Profiler/Hook/constants.cpp index 5d184b6982..09e70f4260 100644 --- a/src/AddIns/Misc/Profiler/Hook/constants.cpp +++ b/src/AddIns/Misc/Profiler/Hook/constants.cpp @@ -18,5 +18,5 @@ WCHAR *winFormsGroupList[WINFORMS_GROUP_LENGTH] = { }; WCHAR *wpfGroupList[WPF_GROUP_LENGTH] = { - L"dummy" + L"System.Windows.UIElement.OnLeftMouseButtonDown" }; \ No newline at end of file diff --git a/src/AddIns/Misc/Profiler/Hook/global.h b/src/AddIns/Misc/Profiler/Hook/global.h index 9c706de4df..75b7e8ccf3 100644 --- a/src/AddIns/Misc/Profiler/Hook/global.h +++ b/src/AddIns/Misc/Profiler/Hook/global.h @@ -40,6 +40,7 @@ struct StackEntry { struct ThreadLocalData { int threadID; volatile int inLock; + volatile bool active; ThreadLocalData *predecessor; ThreadLocalData *follower; diff --git a/src/AddIns/Misc/Profiler/Hook/main.cpp b/src/AddIns/Misc/Profiler/Hook/main.cpp index ad9e18c3bd..e4d08f6761 100644 --- a/src/AddIns/Misc/Profiler/Hook/main.cpp +++ b/src/AddIns/Misc/Profiler/Hook/main.cpp @@ -8,6 +8,7 @@ #include "main.h" #include "global.h" #include "FunctionInfo.h" +#include "ProfilerMetaData.h" //sharedMemoryAllocator mallocator; freeListAllocator mallocator; @@ -43,37 +44,41 @@ STDAPI rdtsc(ULONGLONG *tsc) { return S_OK; } + +std::wstring EscapeString(const WCHAR *input) +{ + std::wostringstream output; + output.str(L""); + + for (const WCHAR *ptr = input; *ptr != 0; ptr++) { + WCHAR c = *ptr; + if (c == '"') + output << "\"\""; + else + output << c; + } + + return output.str(); +} + extern "C" { void __stdcall DeactivateProfiler() { - profiler.LogString(L"DeactivateProfiler called!"); profiler.Deactivate(); } void __stdcall ActivateProfiler() { - profiler.LogString(L"ActivateProfiler called!"); profiler.Activate(); } void __stdcall LogEvent(int type, int id, WCHAR *controlName, WCHAR *controlText) { - WCHAR *format = L""; - - switch (type) { - case 0: - format = L"event %d %d --"; - break; - case 1: - format = L"event %d %d --"; - break; - case 2: - format = L"event %d %d -name:\"%s\"text:\"%s\"-"; - break; - case 3: - break; - } + if (controlName == nullptr) + controlName = L""; + if (controlText == nullptr) + controlText = L""; - DebugWriteLine(format, type, id, controlName, controlText); + profiler.LogString(L"event %d %d \"%s:%s\"", type, id, EscapeString(controlName).c_str(), EscapeString(controlText).c_str()); } } \ No newline at end of file