<commit_before>/*****************************************************************************
* DotNetProfiler
* 
* Copyright (c) 2006 <NAME>
* 
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the author be held liable for any damages arising from the
* use of this software. Permission to use, copy, modify, distribute and sell
* this software for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation.
* 
* <NAME> (<EMAIL>)
*****************************************************************************/
/*
* Copyright (c) 2007-2009 SlimDX Group
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "stdafx.h"
#include "Profiler.h"
#include "NativeHooks.h"
#include "Timer.h"
#include "SigFormat.h"
#include "dbghelp.h"

// global reference to the profiler object (ie this) used by the static functions
ClrProfiler* g_Profiler = NULL;

#define CHECK_HR(hr) if(FAILED(hr)) return (hr);

struct IoThreadFunc
{
	IoThreadFunc(IProfilerServer& server) : m_server(server)
	{ }

	void operator()()
	{
		m_server.Run();
	}

private:
	IProfilerServer& m_server;
};

unsigned int ClassIdFromTypeDefAndModule(mdTypeDef classDef, ModuleID module)
{
	unsigned short classDefLow = classDef & 0xffff;
	unsigned short moduleLow = module & 0xffff;
	unsigned int fullClassId = (moduleLow << 16) | (classDefLow);

	return fullClassId;
}

//This is used to block StackWalk64 from trying to go to disk for symbols, which can cause deadlocks
void* CALLBACK FunctionTableAccess(HANDLE hProcess, DWORD64 AddrBase)
{
	return NULL;
}

ClrProfiler::ClrProfiler()
: m_server(NULL),
m_suspended(0),
m_instDepth(0)
{
#ifdef DEBUG
	__debugbreak();
#endif

	InitializeCriticalSectionAndSpinCount(&m_lock, 200);
	m_modules.reserve(16);
	m_classes.reserve(512);
	m_functions.reserve(4096);

	const wchar_t* invalidName = L"$INVALID$";

	FunctionInfo* invalidFunc = new FunctionInfo(0, 0);
	invalidFunc->Name = invalidName;
	m_functions.push_back(invalidFunc);

	ClassInfo* invalidClass = new ClassInfo(0, 0);
	invalidClass->Name = invalidName;
	m_classes.push_back(invalidClass);

	ModuleInfo* invalidMod = new ModuleInfo(0);
	invalidMod->Name = invalidName;
	m_modules.push_back(invalidMod);
}

ClrProfiler::~ClrProfiler()
{
	DeleteCriticalSection(&m_lock);
}

HRESULT ClrProfiler::FinalConstruct()
{
	return S_OK;
}

void ClrProfiler::FinalRelease()
{
}

STDMETHODIMP ClrProfiler::Initialize(IUnknown *pICorProfilerInfoUnk)
{
	//multiple active profilers are not a supported configuration
	//this is possible with .NET 4.0
	if(g_Profiler != NULL)
		return E_FAIL;

	//Get the COM interfaces
	HRESULT hr = pICorProfilerInfoUnk->QueryInterface(IID_ICorProfilerInfo, (LPVOID*) &m_ProfilerInfo);
	if (FAILED(hr))
		return E_FAIL;

	hr = pICorProfilerInfoUnk->QueryInterface(IID_ICorProfilerInfo2, (LPVOID*) &m_ProfilerInfo2);
	if (FAILED(hr))
	{
		//we've decided not to support .NET before 2.0.
		return E_FAIL;
	}

	//TODO: Query for ICorProfilerInfo3

	m_config.LoadEnv();
	//m_config.SampleUnmanaged = true;
#ifdef X64
	//nothing else supported right now
	m_config.Mode = PM_Sampling;
#endif

	//set up basic profiler info
	hr = SetInitialEventMask();
	assert(SUCCEEDED(hr));

	hr = m_ProfilerInfo2->SetFunctionIDMapper(StaticFunctionMapper);
	assert(SUCCEEDED(hr));

#ifdef X86
	if(m_config.Mode & PM_Tracing)
	{
		hr = m_ProfilerInfo2->SetEnterLeaveFunctionHooks2(FunctionEnterNaked, FunctionLeaveNaked, FunctionTailcallNaked);
		assert(SUCCEEDED(hr));
	}
#endif

	//set up dbghelp
	if(!SymInitializeLocal())
		return E_FAIL;
	SymSetOptionsPtr(SYMOPT_UNDNAME);
	SymInitializePtr(GetCurrentProcess(), NULL, TRUE);

	//CONFIG: Server type?
	m_active = false;
	m_server.reset(IProfilerServer::CreateSocketServer(*this, m_config.ListenPort, m_lock));
	m_server->SetCallbacks(boost::bind(&ClrProfiler::OnConnect, this), boost::bind(&ClrProfiler::OnDisconnect, this));
	m_server->Start();

	//initialize timing (and use cycle timing if enabled and on Vista+)
	InitializeTimer(/*m_config.CycleTiming && m_config.Version.dwMajorVersion >= 6*/ false);

	//initialize counters
	m_counter.reset(new PerfCounter());
	for(size_t i = 0; i < m_config.Counters.size(); ++i)
	{
		int id = m_counter->AddProcessCounter(m_config.Counters[i]);
		SetCounterName(id, m_config.Counters[i]);
	}
	if(m_config.CounterInterval < 10)
		m_config.CounterInterval = 10;
	CreateTimerQueueTimer(&m_counterTimer, NULL, &ClrProfiler::OnCounterTimerGlobal, this,
		m_config.CounterInterval, m_config.CounterInterval, WT_EXECUTEDEFAULT);

	// set up our global access pointer
	g_Profiler = this;<commit_msg>Added the ability to specify a raw counter path using an @ prefix.<commit_after>/*****************************************************************************
* DotNetProfiler
* 
* Copyright (c) 2006 <NAME>
* 
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the author be held liable for any damages arising from the
* use of this software. Permission to use, copy, modify, distribute and sell
* this software for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation.
* 
* <NAME> (<EMAIL>)
*****************************************************************************/
/*
* Copyright (c) 2007-2009 SlimDX Group
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "stdafx.h"
#include "Profiler.h"
#include "NativeHooks.h"
#include "Timer.h"
#include "SigFormat.h"
#include "dbghelp.h"

// global reference to the profiler object (ie this) used by the static functions
ClrProfiler* g_Profiler = NULL;

#define CHECK_HR(hr) if(FAILED(hr)) return (hr);

struct IoThreadFunc
{
	IoThreadFunc(IProfilerServer& server) : m_server(server)
	{ }

	void operator()()
	{
		m_server.Run();
	}

private:
	IProfilerServer& m_server;
};

unsigned int ClassIdFromTypeDefAndModule(mdTypeDef classDef, ModuleID module)
{
	unsigned short classDefLow = classDef & 0xffff;
	unsigned short moduleLow = module & 0xffff;
	unsigned int fullClassId = (moduleLow << 16) | (classDefLow);

	return fullClassId;
}

//This is used to block StackWalk64 from trying to go to disk for symbols, which can cause deadlocks
void* CALLBACK FunctionTableAccess(HANDLE hProcess, DWORD64 AddrBase)
{
	return NULL;
}

ClrProfiler::ClrProfiler()
: m_server(NULL),
m_suspended(0),
m_instDepth(0)
{
#ifdef DEBUG
	__debugbreak();
#endif

	InitializeCriticalSectionAndSpinCount(&m_lock, 200);
	m_modules.reserve(16);
	m_classes.reserve(512);
	m_functions.reserve(4096);

	const wchar_t* invalidName = L"$INVALID$";

	FunctionInfo* invalidFunc = new FunctionInfo(0, 0);
	invalidFunc->Name = invalidName;
	m_functions.push_back(invalidFunc);

	ClassInfo* invalidClass = new ClassInfo(0, 0);
	invalidClass->Name = invalidName;
	m_classes.push_back(invalidClass);

	ModuleInfo* invalidMod = new ModuleInfo(0);
	invalidMod->Name = invalidName;
	m_modules.push_back(invalidMod);
}

ClrProfiler::~ClrProfiler()
{
	DeleteCriticalSection(&m_lock);
}

HRESULT ClrProfiler::FinalConstruct()
{
	return S_OK;
}

void ClrProfiler::FinalRelease()
{
}

STDMETHODIMP ClrProfiler::Initialize(IUnknown *pICorProfilerInfoUnk)
{
	//multiple active profilers are not a supported configuration
	//this is possible with .NET 4.0
	if(g_Profiler != NULL)
		return E_FAIL;

	//Get the COM interfaces
	HRESULT hr = pICorProfilerInfoUnk->QueryInterface(IID_ICorProfilerInfo, (LPVOID*) &m_ProfilerInfo);
	if (FAILED(hr))
		return E_FAIL;

	hr = pICorProfilerInfoUnk->QueryInterface(IID_ICorProfilerInfo2, (LPVOID*) &m_ProfilerInfo2);
	if (FAILED(hr))
	{
		//we've decided not to support .NET before 2.0.
		return E_FAIL;
	}

	//TODO: Query for ICorProfilerInfo3

	m_config.LoadEnv();
	//m_config.SampleUnmanaged = true;
#ifdef X64
	//nothing else supported right now
	m_config.Mode = PM_Sampling;
#endif

	//set up basic profiler info
	hr = SetInitialEventMask();
	assert(SUCCEEDED(hr));

	hr = m_ProfilerInfo2->SetFunctionIDMapper(StaticFunctionMapper);
	assert(SUCCEEDED(hr));

#ifdef X86
	if(m_config.Mode & PM_Tracing)
	{
		hr = m_ProfilerInfo2->SetEnterLeaveFunctionHooks2(FunctionEnterNaked, FunctionLeaveNaked, FunctionTailcallNaked);
		assert(SUCCEEDED(hr));
	}
#endif

	//set up dbghelp
	if(!SymInitializeLocal())
		return E_FAIL;
	SymSetOptionsPtr(SYMOPT_UNDNAME);
	SymInitializePtr(GetCurrentProcess(), NULL, TRUE);

	//CONFIG: Server type?
	m_active = false;
	m_server.reset(IProfilerServer::CreateSocketServer(*this, m_config.ListenPort, m_lock));
	m_server->SetCallbacks(boost::bind(&ClrProfiler::OnConnect, this), boost::bind(&ClrProfiler::OnDisconnect, this));
	m_server->Start();

	//initialize timing (and use cycle timing if enabled and on Vista+)
	InitializeTimer(/*m_config.CycleTiming && m_config.Version.dwMajorVersion >= 6*/ false);

	//initialize counters
	m_counter.reset(new PerfCounter());
	for(size_t i = 0; i < m_config.Counters.size(); ++i)
	{
		int id = 0;
		if(m_config.Counters[i][0] == L'@')
			id = m_counter->AddCounterRaw(m_config.Counters[i].c_str() + 1);
		else
			id = m_counter->AddProcessCounter(m_config.Counters[i]);

		SetCounterName(id, m_config.Counters[i]);
	}
	if(m_config.CounterInterval < 10)
		m_config.CounterInterval = 10;
	CreateTimerQueueTimer(&m_counterTimer, NULL, &ClrProfiler::OnCounterTimerGlobal, this,
		m_config.CounterInterval, m_config.CounterInterval, WT_EXECUTEDEFAULT);

	// set up our global access pointer
	g_Profiler = this;
{'fraction_non_alphanumeric': 0.12617461131043908, 'fraction_numerical': 0.010336579531864001, 'mean_word_length': 5.595492957746479, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 32, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6239776', 'n_tokens_mistral': 3879, 'n_tokens_neox': 3718, 'n_words': 1116}