Browse Source

new options in profiler

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/3.0@3900 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Siegfried Pammer 17 years ago
parent
commit
97eb5487e6
  1. 5
      src/AddIns/Misc/Profiler/Controller/Data/TempFileDatabase.cs
  2. 102
      src/AddIns/Misc/Profiler/Controller/ExtensionMethods.cs
  3. 42
      src/AddIns/Misc/Profiler/Controller/Profiler.cs
  4. 22
      src/AddIns/Misc/Profiler/Controller/ProfilerOptions.cs
  5. 3
      src/AddIns/Misc/Profiler/Controller/structs.cs
  6. 1
      src/AddIns/Misc/Profiler/Frontend/AddIn/AddIn.csproj
  7. 6
      src/AddIns/Misc/Profiler/Frontend/AddIn/Src/Commands/SetAsRoot.cs
  8. 112
      src/AddIns/Misc/Profiler/Frontend/AddIn/Src/ExtensionMethods.cs
  9. 5
      src/AddIns/Misc/Profiler/Frontend/AddIn/Src/OptionsPanels/General.cs
  10. 2
      src/AddIns/Misc/Profiler/Frontend/AddIn/Src/ProfilerRunner.cs
  11. 5
      src/AddIns/Misc/Profiler/Frontend/Gui/Window1.xaml.cs
  12. 76
      src/AddIns/Misc/Profiler/Hook/Profiler.cpp
  13. 100
      src/AddIns/Misc/Profiler/Hook/ProfilerMetaData.cpp
  14. 12
      src/AddIns/Misc/Profiler/Hook/ProfilerMetaData.h
  15. 6
      src/AddIns/Misc/Profiler/Hook/SharedMemory.cpp
  16. 3
      src/AddIns/Misc/Profiler/Hook/SharedMemory.h
  17. 3
      src/AddIns/Misc/Profiler/Hook/global.h

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

@ -94,6 +94,7 @@ namespace ICSharpCode.Profiler.Controller.Data @@ -94,6 +94,7 @@ namespace ICSharpCode.Profiler.Controller.Data
sealed class TempFileDatabaseWriter : IProfilingDataWriter
{
TempFileDatabase database;
bool isClosed;
public TempFileDatabaseWriter(TempFileDatabase database)
{
@ -121,7 +122,9 @@ namespace ICSharpCode.Profiler.Controller.Data @@ -121,7 +122,9 @@ namespace ICSharpCode.Profiler.Controller.Data
public void Close()
{
database.NotifyFinish();
if (!isClosed)
database.NotifyFinish();
isClosed = true;
}
public void WriteMappings(IEnumerable<NameMapping> mappings)

102
src/AddIns/Misc/Profiler/Controller/ExtensionMethods.cs

@ -1,9 +1,12 @@ @@ -1,9 +1,12 @@
using ICSharpCode.Profiler.Controller.Data;
using System;
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using ICSharpCode.Profiler.Controller.Data;
namespace ICSharpCode.Profiler.Controller
{
@ -35,5 +38,100 @@ namespace ICSharpCode.Profiler.Controller @@ -35,5 +38,100 @@ namespace ICSharpCode.Profiler.Controller
{
return items.First().Merge(items);
}
/// <summary>
/// Creates a comma separated string. The string is encoded so that it can be split
/// into the original parts even if the inputs contains commas.
/// </summary>
public static string CreateSeparatedString(this IEnumerable<string> inputs)
{
return CreateSeparatedString(inputs, ',');
}
/// <summary>
/// Creates a separated string using the specified separator. The string is encoded
/// so that it can be split into the original parts even if the inputs contain the separator.
/// </summary>
public static string CreateSeparatedString(this IEnumerable<string> inputs, char separator)
{
if (inputs == null)
throw new ArgumentNullException("inputs");
if (separator == '"')
throw new ArgumentException("Invalid separator");
StringBuilder b = new StringBuilder();
bool first = true;
foreach (string input in inputs) {
if (input == null)
throw new ArgumentNullException("inputs", "An element in inputs is null");
if (first)
first = false;
else
b.Append(separator);
if (input.Length > 0 && input.IndexOf(separator) < 0 && input.IndexOf('"') < 0) {
b.Append(input);
} else {
b.Append('"');
foreach (char c in input) {
if (c == '"')
b.Append("\"\"");
else
b.Append(c);
}
b.Append('"');
}
}
return b.ToString();
}
/// <summary>
/// Splits a comma-separated string.
/// </summary>
public static IList<string> SplitSeparatedString(this string input)
{
return SplitSeparatedString(input, ',');
}
/// <summary>
/// Splits a separated string using the specified separator.
/// </summary>
public static IList<string> SplitSeparatedString(this string input, char separator)
{
if (input == null)
throw new ArgumentNullException("input");
if (separator == '"')
throw new ArgumentException("Invalid separator");
List<string> result = new List<string>();
for (int i = 0; i < input.Length; i++) {
Debug.Assert(i == 0 || input[i - 1] == separator);
if (input[i] == '"') {
i++;
StringBuilder b = new StringBuilder();
for (; i < input.Length; i++) {
char c = input[i];
if (c == '"') {
i++;
if (i < input.Length && input[i] == '"')
b.Append('"');
else
break;
} else {
b.Append(c);
}
}
result.Add(b.ToString());
// i is now positioned before separator
} else {
int end = input.IndexOf(separator, i);
if (end < 0) end = input.Length;
result.Add(input.Substring(i, end - i));
i = end; // position i before separator
}
}
return result;
}
}
}

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

@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
// </file>
using System;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
@ -273,6 +274,8 @@ namespace ICSharpCode.Profiler.Controller @@ -273,6 +274,8 @@ namespace ICSharpCode.Profiler.Controller
memHeader32->HeapOffset = Align(memHeader32->ThreadDataOffset + threadDataSize);
memHeader32->HeapLength = profilerOptions.SharedMemorySize - memHeader32->HeapOffset;
memHeader32->ProcessorFrequency = GetProcessorFrequency();
memHeader32->DoNotProfileDotnetInternals = !profilerOptions.ProfileDotNetInternals;
memHeader32->CombineRecursiveFunction = profilerOptions.CombineRecursiveFunction;
if ((Int32)(fullView.Pointer + memHeader32->HeapOffset) % 8 != 0) {
throw new DataMisalignedException("Heap is not aligned properly: " + ((Int32)(fullView.Pointer + memHeader32->HeapOffset)).ToString(CultureInfo.InvariantCulture) + "!");
@ -575,6 +578,8 @@ namespace ICSharpCode.Profiler.Controller @@ -575,6 +578,8 @@ namespace ICSharpCode.Profiler.Controller
isRunning = false;
this.dataWriter.Close();
OnSessionEnded(EventArgs.Empty);
}
@ -631,27 +636,34 @@ namespace ICSharpCode.Profiler.Controller @@ -631,27 +636,34 @@ namespace ICSharpCode.Profiler.Controller
return false;
if (readString.StartsWith("map ", StringComparison.Ordinal)) {
string[] parts = readString.Split('-');
string[] args = parts[0].Split(' ');
IList<string> parts = readString.SplitSeparatedString(' ');
int id = int.Parse(args[1], CultureInfo.InvariantCulture.NumberFormat);
string name = null;
string returnType = null;
IList<string> parameters = null;
if (parts[1].StartsWith("Thread#", StringComparison.Ordinal)) {
name = parts[1] + ((parts.Length > 2 && !string.IsNullOrEmpty(parts[2])) ? " - " + parts[2] : "");
} else {
returnType = parts[1].Trim();
name = parts[2].Trim();
if (parts.Length > 3)
parameters = parts[3].Trim().Split(new string[] { ", " }, StringSplitOptions.RemoveEmptyEntries);
}
if (parts.Count < 3)
return false;
int id = int.Parse(parts[1], CultureInfo.InvariantCulture);
string name = parts[4];
string returnType = parts[3];
IList<string> parameters = parts.Skip(5).ToList();
lock (this.dataWriter) {
this.dataWriter.WriteMappings(new NameMapping[] {new NameMapping(id, returnType, name, parameters)});
}
return true;
} else if (readString.StartsWith("mapthread ", StringComparison.Ordinal)) {
IList<string> parts = readString.SplitSeparatedString(' ');
if (parts.Count < 5)
return false;
int id = int.Parse(parts[1], CultureInfo.InvariantCulture);
string name = parts[3] + ((string.IsNullOrEmpty(parts[4])) ? "" : " - " + parts[4]);
lock (this.dataWriter) {
this.dataWriter.WriteMappings(new NameMapping[] {new NameMapping(id, null, name, null)});
}
return true;
} else {
if (readString.StartsWith("error-", StringComparison.Ordinal)) {

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

@ -20,8 +20,24 @@ namespace ICSharpCode.Profiler.Controller @@ -20,8 +20,24 @@ namespace ICSharpCode.Profiler.Controller
public const int SHARED_MEMORY_SIZE = 64 * 1024 * 1024; // 64 mb
bool enableDC;
bool profileDotNetInternals;
bool combineRecursiveFunction;
int sharedMemorySize;
/// <summary>
/// Gets whether .NET internal calls are profiled or not.
/// </summary>
public bool ProfileDotNetInternals {
get { return profileDotNetInternals; }
}
/// <summary>
/// Gets whether recursive functions calls are combined or not.
/// </summary>
public bool CombineRecursiveFunction {
get { return combineRecursiveFunction; }
}
/// <summary>
/// Gets whether data collection is enabled during profiling sessions.
/// </summary>
@ -39,17 +55,19 @@ namespace ICSharpCode.Profiler.Controller @@ -39,17 +55,19 @@ namespace ICSharpCode.Profiler.Controller
/// <summary>
/// Creates new ProfilerOptions using the selected settings.
/// </summary>
public ProfilerOptions(bool enableDC, int sharedMemorySize)
public ProfilerOptions(bool enableDC, int sharedMemorySize, bool profileDotNetInternals, bool combineRecursiveFunction)
{
this.enableDC = enableDC;
this.sharedMemorySize = sharedMemorySize;
this.profileDotNetInternals = profileDotNetInternals;
this.combineRecursiveFunction = combineRecursiveFunction;
}
/// <summary>
/// Creates default ProfilerOptions.
/// </summary>
public ProfilerOptions()
: this(true, SHARED_MEMORY_SIZE)
: this(true, SHARED_MEMORY_SIZE, true, false)
{
}
}

3
src/AddIns/Misc/Profiler/Controller/structs.cs

@ -30,6 +30,8 @@ namespace ICSharpCode.Profiler.Controller @@ -30,6 +30,8 @@ namespace ICSharpCode.Profiler.Controller
public TargetProcessPointer32 RootFuncInfoAddress;
public TargetProcessPointer32 LastThreadListItem;
public int ProcessorFrequency;
public bool DoNotProfileDotnetInternals;
public bool CombineRecursiveFunction;
public Allocator32 Allocator;
}
@ -238,5 +240,6 @@ namespace ICSharpCode.Profiler.Controller @@ -238,5 +240,6 @@ namespace ICSharpCode.Profiler.Controller
{
public TargetProcessPointer32 Function;
public ulong StartTime;
public int FrameCount;
}
}

1
src/AddIns/Misc/Profiler/Frontend/AddIn/AddIn.csproj

@ -99,7 +99,6 @@ @@ -99,7 +99,6 @@
<Compile Include="Src\Dialogs\ProfileExecutableForm.xaml.cs">
<DependentUpon>ProfileExecutableForm.xaml</DependentUpon>
</Compile>
<Compile Include="Src\ExtensionMethods.cs" />
<Compile Include="Src\OptionsPanels\General.cs">
<SubType>UserControl</SubType>
</Compile>

6
src/AddIns/Misc/Profiler/Frontend/AddIn/Src/Commands/SetAsRoot.cs

@ -43,10 +43,8 @@ namespace ICSharpCode.Profiler.AddIn.Commands @@ -43,10 +43,8 @@ namespace ICSharpCode.Profiler.AddIn.Commands
foreach (CallTreeNode node in items) {
if (nameId != null && nameId != node.NameMapping.Id)
nameId = null;
NodePath p = node.GetPath().First();
if (p != null) {
parts.Add("GetNodeByPath(" + string.Join(",", p.Select(i => i.ToString()).ToArray()) + ")");
}
foreach (var path in node.GetPath())
parts.Add("GetNodeByPath(" + string.Join(",", path.Select(i => i.ToString()).ToArray()) + ")");
}
string header = "Merged Nodes: " + items.First().Name;

112
src/AddIns/Misc/Profiler/Frontend/AddIn/Src/ExtensionMethods.cs

@ -1,112 +0,0 @@ @@ -1,112 +0,0 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <author name="Daniel Grunwald"/>
// <version>$Revision: 382 $</version>
// </file>
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
namespace ICSharpCode.Profiler.AddIn
{
static class ExtensionMethods
{
/// <summary>
/// Creates a comma separated string. The string is encoded so that it can be split
/// into the original parts even if the inputs contains commas.
/// </summary>
public static string CreateSeparatedString(this IEnumerable<string> inputs)
{
return CreateSeparatedString(inputs, ',');
}
/// <summary>
/// Creates a separated string using the specified separator. The string is encoded
/// so that it can be split into the original parts even if the inputs contain the separator.
/// </summary>
public static string CreateSeparatedString(this IEnumerable<string> inputs, char separator)
{
if (inputs == null)
throw new ArgumentNullException("inputs");
if (separator == '"')
throw new ArgumentException("Invalid separator");
StringBuilder b = new StringBuilder();
bool first = true;
foreach (string input in inputs) {
if (input == null)
throw new ArgumentNullException("inputs", "An element in inputs is null");
if (first)
first = false;
else
b.Append(separator);
if (input.Length > 0 && input.IndexOf(separator) < 0 && input.IndexOf('"') < 0) {
b.Append(input);
} else {
b.Append('"');
foreach (char c in input) {
if (c == '"')
b.Append("\"\"");
else
b.Append(c);
}
b.Append('"');
}
}
return b.ToString();
}
/// <summary>
/// Splits a comma-separated string.
/// </summary>
public static IList<string> SplitSeparatedString(this string input)
{
return SplitSeparatedString(input, ',');
}
/// <summary>
/// Splits a separated string using the specified separator.
/// </summary>
public static IList<string> SplitSeparatedString(this string input, char separator)
{
if (input == null)
throw new ArgumentNullException("input");
if (separator == '"')
throw new ArgumentException("Invalid separator");
List<string> result = new List<string>();
for (int i = 0; i < input.Length; i++) {
Debug.Assert(i == 0 || input[i - 1] == separator);
if (input[i] == '"') {
i++;
StringBuilder b = new StringBuilder();
for (; i < input.Length; i++) {
char c = input[i];
if (c == '"') {
i++;
if (i < input.Length && input[i] == '"')
b.Append('"');
else
break;
} else {
b.Append(c);
}
}
result.Add(b.ToString());
// i is now positioned before separator
} else {
int end = input.IndexOf(separator, i);
if (end < 0) end = input.Length;
result.Add(input.Substring(i, end - i));
i = end; // position i before separator
}
}
return result;
}
}
}

5
src/AddIns/Misc/Profiler/Frontend/AddIn/Src/OptionsPanels/General.cs

@ -52,7 +52,10 @@ namespace ICSharpCode.Profiler.AddIn.OptionsPanels @@ -52,7 +52,10 @@ namespace ICSharpCode.Profiler.AddIn.OptionsPanels
public static ProfilerOptions CreateProfilerOptions()
{
return new ProfilerOptions(properties.Get("EnableDC", true),
properties.Get("SharedMemorySize", ProfilerOptions.SHARED_MEMORY_SIZE));
properties.Get("SharedMemorySize", ProfilerOptions.SHARED_MEMORY_SIZE),
!properties.Get("PorfileDotNetInternals", true),
properties.Get("CombineRecursiveFunction", false)
);
}
}
}

2
src/AddIns/Misc/Profiler/Frontend/AddIn/Src/ProfilerRunner.cs

@ -66,8 +66,6 @@ namespace ICSharpCode.Profiler.AddIn @@ -66,8 +66,6 @@ namespace ICSharpCode.Profiler.AddIn
void FinishSession()
{
profiler.DataWriter.Close();
if (database != null) {
database.WriteTo(writer, progress => true); // TODO : change default impl to good user interface notification
writer.Close();

5
src/AddIns/Misc/Profiler/Frontend/Gui/Window1.xaml.cs

@ -88,7 +88,6 @@ namespace ICSharpCode.Profiler.Frontend @@ -88,7 +88,6 @@ namespace ICSharpCode.Profiler.Frontend
void profiler_SessionEnded(object sender, EventArgs e)
{
string pathToDb = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(typeof(Profiler.Controller.Profiler).Assembly.Location), "output.sdps");
profiler.DataWriter.Close();
ProfilingDataSQLiteWriter writer = new ProfilingDataSQLiteWriter(pathToDb);
this.database.WriteTo(writer, progress => true);
writer.Close();
@ -109,8 +108,8 @@ namespace ICSharpCode.Profiler.Frontend @@ -109,8 +108,8 @@ namespace ICSharpCode.Profiler.Frontend
MessageBox.Show(ex.ToString());
}
}
));
)
);
}
void RefreshUI(int startIndex, int endIndex)

76
src/AddIns/Misc/Profiler/Hook/Profiler.cpp

@ -81,29 +81,34 @@ ASSEMBLER_CALLBACK FunctionEnterGlobal(int functionID) @@ -81,29 +81,34 @@ ASSEMBLER_CALLBACK FunctionEnterGlobal(int functionID)
// this call allows GetOrAddChild to update the value at the top of the stack
// if the FunctionInfo is resized
FunctionInfo *f = data->stack.top().function;
//DebugWriteLine(L"FunctionEnterGlobal %d, current stack top=%d", functionID, f->Id);
FunctionInfo *newParent = nullptr;
FunctionInfo *child = f->GetOrAddChild(functionID, newParent);
if (newParent != nullptr) {
// f was moved to newParent
// update stack:
data->stack.top().function = newParent;
// update parent of f:
if (data->stack.hasAtLeastTwoElements()) {
// DebugWriteLine("Updating parent of parent");
data->stack.belowTop().function->AddOrUpdateChild(newParent);
data->stack.belowTop().function->Check();
} else {
DebugWriteLine(L"Updating parent of parent (root)");
profiler.MovedRootChild(newParent);
if ((sharedMemoryHeader->doNotProfileDotnetInternals && functionID < 0 && f->Id < 0) || (sharedMemoryHeader->combineRecursiveFunction && functionID == f->Id)) {
data->stack.top().frameCount++;
} else {
//DebugWriteLine(L"FunctionEnterGlobal %d, current stack top=%d", functionID, f->Id);
FunctionInfo *newParent = nullptr;
FunctionInfo *child = f->GetOrAddChild(functionID, newParent);
if (newParent != nullptr) {
// f was moved to newParent
// update stack:
data->stack.top().function = newParent;
// update parent of f:
if (data->stack.hasAtLeastTwoElements()) {
//DebugWriteLine("Updating parent of parent");
data->stack.belowTop().function->AddOrUpdateChild(newParent);
data->stack.belowTop().function->Check();
} else {
DebugWriteLine(L"Updating parent of parent (root)");
profiler.MovedRootChild(newParent);
}
FreeFunctionInfo(f);
}
FreeFunctionInfo(f);
// Set the stats for this function
child->CallCount++;
data->stack.push(StackEntry(child, __rdtsc()));
}
// Set the stats for this function
child->CallCount++;
data->stack.push(StackEntry(child, __rdtsc()));
data->inLock = 0;
}
@ -132,8 +137,11 @@ ASSEMBLER_CALLBACK FunctionLeaveGlobal() @@ -132,8 +137,11 @@ ASSEMBLER_CALLBACK FunctionLeaveGlobal()
} else {
StackEntry &stackTop = data->stack.top();
//DebugWriteLine(L"FunctionLeaveGlobal %d", stackTop.function->Id);
stackTop.function->TimeSpent += (__rdtsc() - stackTop.startTime);
data->stack.pop();
stackTop.frameCount--;
if (stackTop.frameCount == 0) {
stackTop.function->TimeSpent += (__rdtsc() - stackTop.startTime);
data->stack.pop();
}
}
data->inLock = 0;
@ -149,9 +157,9 @@ ASSEMBLER_CALLBACK FunctionTailcallGlobal() @@ -149,9 +157,9 @@ ASSEMBLER_CALLBACK FunctionTailcallGlobal()
// FunctionTailcallGlobal call will be followed by FunctionEnterGlobal for new function
}
volatile LONG nextFunctionID = 0;
volatile LONG nextPosFunctionID = 0;
int getNewFunctionID() {
int getNewPosFunctionID() {
const int step = 5;
// Simple continuous assignment of IDs leads to problems with the
// linear probing in FunctionInfo, so we use multiples of 'step' as IDs.
@ -159,9 +167,9 @@ int getNewFunctionID() { @@ -159,9 +167,9 @@ int getNewFunctionID() {
LONG oldID;
LONG newID;
do {
oldID = nextFunctionID;
newID = oldID + step;
} while (InterlockedCompareExchange(&nextFunctionID, newID, oldID) != oldID);
oldID = nextPosFunctionID;
newID = ((oldID + step) & 0x7FFFFFFF); // x % 2^31
} while (InterlockedCompareExchange(&nextPosFunctionID, newID, oldID) != oldID);
return newID;
}
@ -175,15 +183,19 @@ UINT_PTR CProfiler::MapFunction(FunctionID functionID) @@ -175,15 +183,19 @@ UINT_PTR CProfiler::MapFunction(FunctionID functionID)
{
mapFunctionCriticalSection.Enter();
int clientData = 0;
TFunctionIDMap::iterator it = this->functionIDMap.find(functionID);
if (it == this->functionIDMap.end()) {
DebugWriteLine(L"Creating new ID");
clientData = getNewFunctionID();
if (sigReader->IsNetInternal(functionID))
clientData = -getNewPosFunctionID(); // negative series
else
clientData = getNewPosFunctionID(); // positive series
this->functionIDMap.insert(TFunctionIDPair(functionID, clientData));
// send to host
std::wstring signature = sigReader->Parse(functionID);
LogString(L"map %d %Id -%s-", clientData, functionID, signature.c_str());
LogString(L"map %d %Id %s", clientData, functionID, signature.c_str());
} else {
DebugWriteLine(L"using old ID");
clientData = it->second;
@ -197,7 +209,7 @@ FunctionInfo *CProfiler::CreateNewRoot() { @@ -197,7 +209,7 @@ FunctionInfo *CProfiler::CreateNewRoot() {
rootElementCriticalSection.Enter();
FunctionInfo *oldRoot = sharedMemoryHeader->RootFuncInfo;
FunctionInfo *newRoot = nullptr;
FunctionInfo *newThreadRoot = oldRoot->GetOrAddChild(getNewFunctionID(), newRoot);
FunctionInfo *newThreadRoot = oldRoot->GetOrAddChild(getNewPosFunctionID(), newRoot);
if (newRoot != nullptr) {
sharedMemoryHeader->RootFuncInfo = newRoot;
FreeFunctionInfo(oldRoot);
@ -208,7 +220,7 @@ FunctionInfo *CProfiler::CreateNewRoot() { @@ -208,7 +220,7 @@ FunctionInfo *CProfiler::CreateNewRoot() {
data->functionInfoId = newThreadRoot->Id;
LogString(L"map %d 0 -Thread#%d-%s-", newThreadRoot->Id, GetCurrentThreadId(), data->threadName.c_str());
LogString(L"mapthread %d 0 \"Thread#%d\" \"%s\"", newThreadRoot->Id, GetCurrentThreadId(), data->threadName.c_str());
return newThreadRoot;
}

100
src/AddIns/Misc/Profiler/Hook/ProfilerMetaData.cpp

@ -156,11 +156,14 @@ bool SignatureReader::ReadMethodDefSig(byte head) @@ -156,11 +156,14 @@ bool SignatureReader::ReadMethodDefSig(byte head)
// Append Name
this->output << L"-";
this->output << className.str();
this->output << L" ";
this->output << '"';
std::wstring name = className.str();
AppendEscapedString(name);
this->output << L".";
this->output << szFunction;
this->output << L"-";
AppendEscapedString(szFunction);
this->output << '"';
this->output << L" ";
// Read Parameters
// Param ::= CustomMod* ( TYPEDBYREF | [BYREF] Type )
@ -188,6 +191,7 @@ bool SignatureReader::ReadMethodDefSig(byte head) @@ -188,6 +191,7 @@ bool SignatureReader::ReadMethodDefSig(byte head)
if (!FAILED(this->metaData->GetParamForMethodIndex(this->methodDefiniton, i + 1, &paramDef))) {
if (!FAILED(this->metaData->GetParamProps(paramDef, &this->methodDefiniton, &pSequence, paramName, 256, &pchName, &pdwAttr, &pdwCPlusTypeFlag, &ppValue, &pcchValue))) {
this->output << '"';
switch (type) {
case ELEMENT_TYPE_TYPEDBYREF:
// ignore
@ -205,12 +209,13 @@ bool SignatureReader::ReadMethodDefSig(byte head) @@ -205,12 +209,13 @@ bool SignatureReader::ReadMethodDefSig(byte head)
}
this->output << L" ";
this->output << paramName;
AppendEscapedString(paramName);
this->output << '"';
}
}
if (i < paramCount - 1)
this->output << L", ";
this->output << L" ";
}
return true;
@ -297,12 +302,12 @@ bool SignatureReader::ReadType(byte type) @@ -297,12 +302,12 @@ bool SignatureReader::ReadType(byte type)
hr = this->metaData->GetTypeRefProps(token, nullptr, zName, 1024, &length);
hr = this->metaData->GetTypeDefProps(token, zName, 1024, &length, nullptr, nullptr);
if (SUCCEEDED(hr) && length > 0)
this->output << zName;
AppendEscapedString(zName);
else {
hr = this->metaData->GetTypeRefProps(token, nullptr, zName, 1024, &length);
hr = this->metaData->GetTypeDefProps(token, zName, 1024, &length, nullptr, nullptr);
if (SUCCEEDED(hr) && length > 0)
this->output << zName;
AppendEscapedString(zName);
else
this->output << L"?";
}
@ -345,7 +350,7 @@ bool SignatureReader::ReadType(byte type) @@ -345,7 +350,7 @@ bool SignatureReader::ReadType(byte type)
hr = this->metaData->GetTypeRefProps(token, nullptr, zName, 1024, &length);
hr = this->metaData->GetTypeDefProps(token, zName, 1024, &length, nullptr, nullptr);
if (SUCCEEDED(hr) && length > 0)
this->output << zName;
AppendEscapedString(zName);
else
this->output << L"?";
if (!this->ReadCompressedInt(&tmp2))
@ -359,7 +364,7 @@ bool SignatureReader::ReadType(byte type) @@ -359,7 +364,7 @@ bool SignatureReader::ReadType(byte type)
return false;
this->ReadType(type);
if ((i + 1) < genArgCount)
this->output << L", ";
this->output << L",";
}
this->output << L">";
break;
@ -520,3 +525,78 @@ bool SignatureReader::ReadCompressedInt(int *out) @@ -520,3 +525,78 @@ bool SignatureReader::ReadCompressedInt(int *out)
*out = ((byte1 & 0x1f) << 24) | (byte2 << 16) | (byte3 << 8) | byte4;
return true;
}
const byte mscorlibkey[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
const byte systemdrawingkey[] = {
0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x06, 0x02, 0x00, 0x00, 0x00,
0x24, 0x00, 0x00, 0x52, 0x53, 0x41, 0x31, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x07, 0xD1,
0xFA, 0x57, 0xC4, 0xAE, 0xD9, 0xF0, 0xA3, 0x2E, 0x84, 0xAA, 0x0F, 0xAE, 0xFD, 0x0D, 0xE9, 0xE8, 0xFD,
0x6A, 0xEC, 0x8F, 0x87, 0xFB, 0x03, 0x76, 0x6C, 0x83, 0x4C, 0x99, 0x92, 0x1E, 0xB2, 0x3B, 0xE7, 0x9A,
0xD9, 0xD5, 0xDC, 0xC1, 0xDD, 0x9A, 0xD2, 0x36, 0x13, 0x21, 0x02, 0x90, 0x0B, 0x72, 0x3C, 0xF9, 0x80,
0x95, 0x7F, 0xC4, 0xE1, 0x77, 0x10, 0x8F, 0xC6, 0x07, 0x77, 0x4F, 0x29, 0xE8, 0x32, 0x0E, 0x92, 0xEA,
0x05, 0xEC, 0xE4, 0xE8, 0x21, 0xC0, 0xA5, 0xEF, 0xE8, 0xF1, 0x64, 0x5C, 0x4C, 0x0C, 0x93, 0xC1, 0xAB,
0x99, 0x28, 0x5D, 0x62, 0x2C, 0xAA, 0x65, 0x2C, 0x1D, 0xFA, 0xD6, 0x3D, 0x74, 0x5D, 0x6F, 0x2D, 0xE5,
0xF1, 0x7E, 0x5E, 0xAF, 0x0F, 0xC4, 0x96, 0x3D, 0x26, 0x1C, 0x8A, 0x12, 0x43, 0x65, 0x18, 0x20, 0x6D,
0xC0, 0x93, 0x34, 0x4D, 0x5A, 0xD2, 0x93
};
bool SignatureReader::IsNetInternal(FunctionID fid)
{
mdToken funcToken;
HRESULT hr = S_OK;
IMetaDataAssemblyImport *asmMetaData;
const void *publicKey;
ULONG pKLength;
hr = profilerInfo->GetTokenAndMetaDataFromFunction(fid, IID_IMetaDataAssemblyImport, (LPUNKNOWN *) &asmMetaData, &funcToken);
if (SUCCEEDED(hr)) {
mdAssembly assembly;
hr = asmMetaData->GetAssemblyFromScope(&assembly);
if (SUCCEEDED(hr)) {
WCHAR assemblyName[NAME_BUFFER_SIZE];
ULONG assemblyNameLength;
hr = asmMetaData->GetAssemblyProps(assembly, &publicKey, &pKLength, nullptr, assemblyName, NAME_BUFFER_SIZE, &assemblyNameLength, nullptr, nullptr);
DebugWriteLine(L"assembly: %s", assemblyName);
const byte *b = (const byte *)publicKey;
WCHAR tmp[8];
std::wstring s(L"{ ");
for (ULONG i = 0; i < pKLength; i++) {
memset(tmp, 0, 16);
swprintf_s(tmp, L"0x%02X, ", (int) b[i]);
s.append(tmp);
}
s.append(L" }");
DebugWriteLine(L"assembly: PK: %s", s.c_str());
if (pKLength == sizeof(mscorlibkey) && memcmp(mscorlibkey, b, sizeof(mscorlibkey)) == 0)
return true;
if (pKLength == sizeof(systemdrawingkey) && memcmp(systemdrawingkey, b, sizeof(systemdrawingkey)) == 0)
return true;
}
}
return false;
}
void SignatureReader::AppendEscapedString(const WCHAR *input)
{
for (const WCHAR *ptr = input; *ptr != 0; ptr++) {
WCHAR c = *ptr;
if (c == '"')
this->output << "\"\"";
else
this->output << c;
}
}
void SignatureReader::AppendEscapedString(const std::wstring &input_string)
{
AppendEscapedString(input_string.c_str());
}

12
src/AddIns/Misc/Profiler/Hook/ProfilerMetaData.h

@ -99,8 +99,16 @@ class SignatureReader { @@ -99,8 +99,16 @@ class SignatureReader {
bool ReadShapedArray(byte);
bool ReadSzArray(byte);
bool ReadArrayType(byte);
/// <summary>
/// Creates a separated string using the specified separator. The string is encoded
/// so that it can be split into the original parts even if the inputs contain the separator.
/// </summary>
void AppendEscapedString(const WCHAR *input);
void AppendEscapedString(const std::wstring &input);
public:
std::wstring Parse(FunctionID);
std::wstring Parse(FunctionID);
bool IsNetInternal(FunctionID);
SignatureReader(ICorProfilerInfo *);
};

6
src/AddIns/Misc/Profiler/Hook/SharedMemory.cpp

@ -19,11 +19,11 @@ CSharedMemory::CSharedMemory(char *name) @@ -19,11 +19,11 @@ CSharedMemory::CSharedMemory(char *name)
DebugWriteLine(L"MapViewOfFile returned nullptr");
MessageBox(nullptr, TEXT("Could not open Shared Memory, please restart the profiler!"), TEXT("Profiler Error"), MB_OK);
}
SharedMemoryHeader* header = (SharedMemoryHeader*)this->startPtr;
if (header->Magic != '~SM1') {
this->header = (SharedMemoryHeader*)this->startPtr;
if (this->header->Magic != '~SM1') {
DebugWriteLine(L"Corrupted shared memory header");
}
this->length = header->TotalLength;
this->length = this->header->TotalLength;
UnmapViewOfFile(this->startPtr);
this->startPtr = MapViewOfFile(this->fileHandle, FILE_MAP_ALL_ACCESS, 0, 0, this->length);
if (startPtr == nullptr) {

3
src/AddIns/Misc/Profiler/Hook/SharedMemory.h

@ -26,6 +26,8 @@ struct SharedMemoryHeader @@ -26,6 +26,8 @@ struct SharedMemoryHeader
FunctionInfo* RootFuncInfo;
ThreadLocalData* LastThreadListItem;
int ProcFrequency;
bool doNotProfileDotnetInternals;
bool combineRecursiveFunction;
freeListAllocator<FunctionInfoAllocationSize> mallocator;
};
@ -35,6 +37,7 @@ public: @@ -35,6 +37,7 @@ public:
CSharedMemory(TCHAR *name);
~CSharedMemory();
void* GetStartPtr();
SharedMemoryHeader *header;
private:
HANDLE fileHandle;
void* startPtr;

3
src/AddIns/Misc/Profiler/Hook/global.h

@ -23,9 +23,10 @@ extern DWORD tls_index; @@ -23,9 +23,10 @@ extern DWORD tls_index;
struct StackEntry {
FunctionInfo *function;
ULONGLONG startTime;
int frameCount;
StackEntry() {}
StackEntry(FunctionInfo * function, ULONGLONG startTime) : function(function), startTime(startTime) {}
StackEntry(FunctionInfo * function, ULONGLONG startTime) : function(function), startTime(startTime), frameCount(1) {}
};
struct ThreadLocalData {

Loading…
Cancel
Save