added amb256 - (nice number), profiler complete with gui to show files
authorDavid Anderson <dvander@alliedmods.net>
Sun Mar 02 06:40:59 2008 +0000 (2008-03-02)
changeset 1908318e0a01aef9
parent 1907 34f148f94339
child 1909 d7f4f60b8a03
added amb256 - (nice number), profiler complete with gui to show files
configs/plugin_settings.cfg
core/Profiler.cpp
core/Profiler.h
core/msvc8/sourcemod_mm.vcproj
core/systems/PluginSys.cpp
core/vm/sp_vm_basecontext.cpp
core/vm/sp_vm_basecontext.h
core/vm/sp_vm_function.cpp
core/vm/sp_vm_function.h
public/sourcepawn/sp_vm_api.h
public/sourcepawn/sp_vm_types.h
sourcepawn/jit/x86/dll_exports.cpp
sourcepawn/jit/x86/jit_x86.cpp
sourcepawn/jit/x86/jit_x86.h
tools/profiler/csharp/Comparators.cs
tools/profiler/csharp/Form1.Designer.cs
tools/profiler/csharp/Form1.cs
tools/profiler/csharp/Form1.resx
tools/profiler/csharp/ProfReport.cs
tools/profiler/csharp/Program.cs
tools/profiler/csharp/profviewer.csproj
tools/profiler/csharp/profviewer.sln
tools/profiler/php/ProfFileParser.class.php
     1.1 --- a/configs/plugin_settings.cfg	Sat Mar 01 07:59:53 2008 +0000
     1.2 +++ b/configs/plugin_settings.cfg	Sun Mar 02 06:40:59 2008 +0000
     1.3 @@ -14,6 +14,13 @@
     1.4   *
     1.5   * You can also have an "Options" section declaring options to pass onto the JIT:
     1.6   * "debug"		- Whether or not to load the plugin in debug mode
     1.7 + * "profile"	- Bit flags for profiling level.  Add flags together to reach a value.
     1.8 + *				  WARNING: Profiler is _ALPHA_ software!  Use it at your own risk for 
     1.9 + *				  development cycles only (not production setups).
    1.10 + *				  See the wiki article "SourceMod Profiler" for more information.
    1.11 + *				  1 - Profile natives
    1.12 + *				  2 - Profile callbacks
    1.13 + *				  4 - Profile internal plugin function calls
    1.14   */
    1.15  	
    1.16  "Plugins"
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/core/Profiler.cpp	Sun Mar 02 06:40:59 2008 +0000
     2.3 @@ -0,0 +1,483 @@
     2.4 +/**
     2.5 + * vim: set ts=4 :
     2.6 + * =============================================================================
     2.7 + * SourceMod
     2.8 + * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
     2.9 + * =============================================================================
    2.10 + *
    2.11 + * This program is free software; you can redistribute it and/or modify it under
    2.12 + * the terms of the GNU General Public License, version 3.0, as published by the
    2.13 + * Free Software Foundation.
    2.14 + * 
    2.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
    2.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    2.17 + * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    2.18 + * details.
    2.19 + *
    2.20 + * You should have received a copy of the GNU General Public License along with
    2.21 + * this program.  If not, see <http://www.gnu.org/licenses/>.
    2.22 + *
    2.23 + * As a special exception, AlliedModders LLC gives you permission to link the
    2.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
    2.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    2.26 + * by the Valve Corporation.  You must obey the GNU General Public License in
    2.27 + * all respects for all other code used.  Additionally, AlliedModders LLC grants
    2.28 + * this exception to all derivative works.  AlliedModders LLC defines further
    2.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    2.30 + * or <http://www.sourcemod.net/license.php>.
    2.31 + *
    2.32 + * Version: $Id$
    2.33 + */
    2.34 +
    2.35 +#include "Profiler.h"
    2.36 +#include "PluginSys.h"
    2.37 +#include "sm_stringutil.h"
    2.38 +#include "Logger.h"
    2.39 +
    2.40 +ProfileEngine g_Profiler;
    2.41 +IProfiler *sm_profiler = &g_Profiler;
    2.42 +
    2.43 +#if defined PLATFORM_WINDOWS
    2.44 +double WINDOWS_PERFORMANCE_FREQUENCY;
    2.45 +#endif
    2.46 +
    2.47 +class EmptyProfiler : public IProfiler
    2.48 +{
    2.49 +public:
    2.50 +	void OnNativeBegin(IPluginContext *pContext, sp_native_t *native)
    2.51 +	{
    2.52 +	}
    2.53 +	void OnNativeEnd()
    2.54 +	{
    2.55 +	}
    2.56 +	void OnFunctionBegin(IPluginContext *pContext, const char *name)
    2.57 +	{
    2.58 +	}
    2.59 +	void OnFunctionEnd()
    2.60 +	{
    2.61 +	}
    2.62 +	int OnCallbackBegin(IPluginContext *pContext, sp_public_t *pubfunc)
    2.63 +	{
    2.64 +		return 0;
    2.65 +	}
    2.66 +	void OnCallbackEnd(int serial)
    2.67 +	{
    2.68 +	}
    2.69 +} s_EmptyProfiler;
    2.70 +
    2.71 +inline void InitProfPoint(prof_point_t &pt)
    2.72 +{
    2.73 +#if defined PLATFORM_WINDOWS
    2.74 +	QueryPerformanceCounter(&pt.value);
    2.75 +#elif defined PLATFORM_POSIX
    2.76 +	gettimeofday(&pt.value, NULL);
    2.77 +#endif
    2.78 +	pt.is_set = true;
    2.79 +}
    2.80 +
    2.81 +ProfileEngine::ProfileEngine()
    2.82 +{
    2.83 +	m_serial = 0;
    2.84 +
    2.85 +#if defined PLATFORM_WINDOWS
    2.86 +	LARGE_INTEGER pf;
    2.87 +
    2.88 +	if (QueryPerformanceFrequency(&pf))
    2.89 +	{
    2.90 +		WINDOWS_PERFORMANCE_FREQUENCY = 1.0 / (double)(pf.QuadPart);
    2.91 +	}
    2.92 +	else
    2.93 +	{
    2.94 +		WINDOWS_PERFORMANCE_FREQUENCY = -1.0;
    2.95 +	}
    2.96 +#endif
    2.97 +
    2.98 +	if (IsEnabled())
    2.99 +	{
   2.100 +		InitProfPoint(m_ProfStart);
   2.101 +	}
   2.102 +	else
   2.103 +	{
   2.104 +		sm_profiler = &s_EmptyProfiler;
   2.105 +	}
   2.106 +}
   2.107 +
   2.108 +bool ProfileEngine::IsEnabled()
   2.109 +{
   2.110 +#if defined PLATFORM_WINDOWS
   2.111 +	return (WINDOWS_PERFORMANCE_FREQUENCY > 0.0);
   2.112 +#elif defined PLATFORM_POSIX
   2.113 +	return true;
   2.114 +#endif
   2.115 +}
   2.116 +
   2.117 +inline double DiffProfPoints(const prof_point_t &start, const prof_point_t &end)
   2.118 +{
   2.119 +	double seconds;
   2.120 +
   2.121 +#if defined PLATFORM_WINDOWS
   2.122 +	LONGLONG diff;
   2.123 +	
   2.124 +	diff = end.value.QuadPart - start.value.QuadPart;
   2.125 +	seconds = diff * WINDOWS_PERFORMANCE_FREQUENCY;
   2.126 +#elif defined PLATFORM_POSIX
   2.127 +	seconds = (double)(end.value.tv_sec - start.value.tv_sec);
   2.128 +
   2.129 +	if (start.value.tv_usec > after.value.tv_usec)
   2.130 +	{
   2.131 +		seconds - 1.0;
   2.132 +		seconds += (double)(1000000 - (before.value.tv_usec - after.tv_usec)) / 1000000.0;
   2.133 +	}
   2.134 +	else
   2.135 +	{
   2.136 +		seconds += (double)(after.value.tv_usec - before.value.tv_usec) / 1000000.0;
   2.137 +	}
   2.138 +#endif
   2.139 +
   2.140 +	return seconds;
   2.141 +}
   2.142 +
   2.143 +inline double CalcAtomTime(const prof_atom_t &atom)
   2.144 +{
   2.145 +	if (!atom.end.is_set)
   2.146 +	{
   2.147 +		return atom.base_time;
   2.148 +	}
   2.149 +
   2.150 +	return atom.base_time + DiffProfPoints(atom.start, atom.end);
   2.151 +}
   2.152 +
   2.153 +void ProfileEngine::OnNativeBegin(IPluginContext *pContext, sp_native_t *native)
   2.154 +{
   2.155 +	PushProfileStack(pContext, SP_PROF_NATIVES, native->name);
   2.156 +}
   2.157 +
   2.158 +void ProfileEngine::OnNativeEnd()
   2.159 +{
   2.160 +	assert(!m_AtomStack.empty());
   2.161 +	assert(m_AtomStack.front().atom_type == SP_PROF_NATIVES);
   2.162 +
   2.163 +	PopProfileStack(&m_Natives);
   2.164 +}
   2.165 +
   2.166 +void ProfileEngine::OnFunctionBegin(IPluginContext *pContext, const char *name)
   2.167 +{
   2.168 +	PushProfileStack(pContext, SP_PROF_FUNCTIONS, name);
   2.169 +}
   2.170 +
   2.171 +void ProfileEngine::OnFunctionEnd()
   2.172 +{
   2.173 +	assert(!m_AtomStack.empty());
   2.174 +	assert(m_AtomStack.front().atom_type == SP_PROF_FUNCTIONS);
   2.175 +
   2.176 +	PopProfileStack(&m_Functions);
   2.177 +}
   2.178 +
   2.179 +int ProfileEngine::OnCallbackBegin(IPluginContext *pContext, sp_public_t *pubfunc)
   2.180 +{
   2.181 +	PushProfileStack(pContext, SP_PROF_CALLBACKS, pubfunc->name);
   2.182 +
   2.183 +	return m_serial;
   2.184 +}
   2.185 +
   2.186 +void ProfileEngine::OnCallbackEnd(int serial)
   2.187 +{
   2.188 +	assert(!m_AtomStack.empty());
   2.189 +
   2.190 +	/**
   2.191 +	 * Account for the situation where the JIT discards the 
   2.192 +	 * stack because there was an RTE of sorts.
   2.193 +	 */
   2.194 +	if (m_AtomStack.front().atom_type != SP_PROF_CALLBACKS
   2.195 +		&& m_AtomStack.front().atom_serial != serial)
   2.196 +	{
   2.197 +		prof_atom_t atom;
   2.198 +		double total_time;
   2.199 +
   2.200 +		/* There was an error, and we need to discard things. */
   2.201 +		total_time = 0.0;
   2.202 +		while (!m_AtomStack.empty() 
   2.203 +			&& m_AtomStack.front().atom_type != SP_PROF_CALLBACKS 
   2.204 +			&& m_AtomStack.front().atom_serial != serial)
   2.205 +		{
   2.206 +			total_time += CalcAtomTime(m_AtomStack.front());
   2.207 +			m_AtomStack.pop();
   2.208 +		}
   2.209 +
   2.210 +		/**
   2.211 +		 * Now we can end and discard ourselves, without saving the data.
   2.212 +		 * Since this data is all erroneous anyway, we don't care if it's 
   2.213 +		 * not totally accurate. 
   2.214 +		 */
   2.215 +
   2.216 +		assert(!m_AtomStack.empty());
   2.217 +		atom = m_AtomStack.front();
   2.218 +		m_AtomStack.pop();
   2.219 +
   2.220 +		/* Note: We don't need to resume ourselves because end is set by Pause(). */
   2.221 +		total_time += CalcAtomTime(atom);
   2.222 +
   2.223 +		ResumeParent(total_time);
   2.224 +		return;
   2.225 +	}
   2.226 +
   2.227 +	PopProfileStack(&m_Callbacks);
   2.228 +}
   2.229 +
   2.230 +void ProfileEngine::PushProfileStack(IPluginContext *ctx, int type, const char *name)
   2.231 +{
   2.232 +	prof_atom_t atom;
   2.233 +
   2.234 +	PauseParent();
   2.235 +
   2.236 +	atom.atom_type = type;
   2.237 +	atom.base_time = 0.0;
   2.238 +	atom.ctx = ctx->GetContext();
   2.239 +	atom.name = name;
   2.240 +	atom.end.is_set = false;
   2.241 +
   2.242 +	if (type == SP_PROF_CALLBACKS)
   2.243 +	{
   2.244 +		atom.atom_serial = ++m_serial;
   2.245 +	}
   2.246 +	else
   2.247 +	{
   2.248 +		atom.atom_serial = 0;
   2.249 +	}
   2.250 +
   2.251 +	m_AtomStack.push(atom);
   2.252 +
   2.253 +	/* Note: We do this after because the stack could grow and skew results */
   2.254 +	InitProfPoint(m_AtomStack.front().start);
   2.255 +}
   2.256 +
   2.257 +void ProfileEngine::PopProfileStack(ProfileReport *reporter)
   2.258 +{
   2.259 +	double total_time;
   2.260 +
   2.261 +	prof_atom_t &atom = m_AtomStack.front();
   2.262 +
   2.263 +	/* We're okay to cache our used time. */
   2.264 +	InitProfPoint(atom.end);
   2.265 +	total_time = CalcAtomTime(atom);
   2.266 +
   2.267 +	/* Now it's time to save this! This may do a lot of computations which 
   2.268 +	 * is why we've cached the time beforehand.
   2.269 +	 */
   2.270 +	reporter->SaveAtom(atom);
   2.271 +	m_AtomStack.pop();
   2.272 +
   2.273 +	/* Finally, tell our parent how much time we used. */
   2.274 +	ResumeParent(total_time);
   2.275 +}
   2.276 +
   2.277 +void ProfileEngine::PauseParent()
   2.278 +{
   2.279 +	if (m_AtomStack.empty())
   2.280 +	{
   2.281 +		return;
   2.282 +	}
   2.283 +
   2.284 +	InitProfPoint(m_AtomStack.front().end);
   2.285 +}
   2.286 +
   2.287 +void ProfileEngine::ResumeParent(double addTime)
   2.288 +{
   2.289 +	if (m_AtomStack.empty())
   2.290 +	{
   2.291 +		return;
   2.292 +	}
   2.293 +
   2.294 +	prof_atom_t &atom = m_AtomStack.front();
   2.295 +
   2.296 +	/* Move its "paused time" to its base (known) time, 
   2.297 +	 * then reset the start/end.  Note that since CalcAtomTime() 
   2.298 +	 * reads the base time, we SHOULD NOT use += to add.
   2.299 +	 */
   2.300 +	atom.base_time = CalcAtomTime(atom);
   2.301 +	atom.base_time += addTime;
   2.302 +	InitProfPoint(atom.start);
   2.303 +	atom.end.is_set = false;
   2.304 +}
   2.305 +
   2.306 +void ProfileEngine::Clear()
   2.307 +{
   2.308 +	m_Natives.Clear();
   2.309 +	m_Callbacks.Clear();
   2.310 +	m_Functions.Clear();
   2.311 +	InitProfPoint(m_ProfStart);
   2.312 +}
   2.313 +
   2.314 +void ProfileEngine::OnSourceModAllInitialized()
   2.315 +{
   2.316 +	g_RootMenu.AddRootConsoleCommand("profiler", "Profiler commands", this);
   2.317 +}
   2.318 +
   2.319 +void ProfileEngine::OnSourceModShutdown()
   2.320 +{
   2.321 +	g_RootMenu.RemoveRootConsoleCommand("profiler", this);
   2.322 +}
   2.323 +
   2.324 +void ProfileEngine::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
   2.325 +{
   2.326 +	if (command.ArgC() >= 3)
   2.327 +	{
   2.328 +		if (strcmp(command.Arg(2), "flush") == 0)
   2.329 +		{
   2.330 +			FILE *fp;
   2.331 +			char path[256];
   2.332 +
   2.333 +			g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "logs/profile_%d.xml", (int)time(NULL));
   2.334 +
   2.335 +			if ((fp = fopen(path, "wt")) == NULL)
   2.336 +			{
   2.337 +				g_RootMenu.ConsolePrint("Failed, could not open file for writing: %s", path);
   2.338 +				return;
   2.339 +			}
   2.340 +
   2.341 +			GenerateReport(fp);
   2.342 +
   2.343 +			fclose(fp);
   2.344 +
   2.345 +			g_RootMenu.ConsolePrint("Profiler report generated as: %s\n", path);
   2.346 +
   2.347 +			return;
   2.348 +		}
   2.349 +	}
   2.350 +
   2.351 +	g_RootMenu.ConsolePrint("Profiler commands:");
   2.352 +	g_RootMenu.DrawGenericOption("flush", "Flushes statistics to disk and starts over");
   2.353 +}
   2.354 +
   2.355 +bool ProfileEngine::GenerateReport(FILE *fp)
   2.356 +{
   2.357 +	time_t t;
   2.358 +	double total_time;
   2.359 +	prof_point_t end_time;
   2.360 +
   2.361 +	InitProfPoint(end_time);
   2.362 +	total_time = DiffProfPoints(m_ProfStart, end_time);
   2.363 +
   2.364 +	t = time(NULL);
   2.365 +
   2.366 +	fprintf(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n");
   2.367 +	fprintf(fp, "<profile time=\"%d\" uptime=\"%f\">\n", (int)t, total_time);
   2.368 +	WriteReport(fp, &m_Natives, "natives");
   2.369 +	WriteReport(fp, &m_Callbacks, "callbacks");
   2.370 +	WriteReport(fp, &m_Functions, "functions");
   2.371 +	fprintf(fp, "</profile>\n");
   2.372 +
   2.373 +	return true;
   2.374 +}
   2.375 +
   2.376 +void ProfileEngine::WriteReport(FILE *fp, ProfileReport *report, const char *name)
   2.377 +{
   2.378 +	size_t i, num;
   2.379 +	prof_atom_report_t *ar;
   2.380 +	char new_name[512];
   2.381 +
   2.382 +	fprintf(fp, " <report name=\"%s\">\n", name);
   2.383 +	
   2.384 +	num = report->GetNumReports();
   2.385 +	for (i = 0; i < num; i++)
   2.386 +	{
   2.387 +		ar = report->GetReport(i);
   2.388 +
   2.389 +		strncopy(new_name, ar->atom_name, sizeof(new_name));
   2.390 +		UTIL_ReplaceAll(new_name, sizeof(new_name), "<", "&lt;");
   2.391 +		UTIL_ReplaceAll(new_name, sizeof(new_name), ">", "&gt;");
   2.392 +
   2.393 +		fprintf(fp, "  <item name=\"%s\" numcalls=\"%d\" mintime=\"%f\" maxtime=\"%f\" totaltime=\"%f\"/>\n", 
   2.394 +			new_name,
   2.395 +			ar->num_calls,
   2.396 +			ar->min_time,
   2.397 +			ar->max_time,
   2.398 +			ar->total_time);
   2.399 +	}
   2.400 +
   2.401 +	fprintf(fp, " </report>\n");
   2.402 +}
   2.403 +
   2.404 +ProfileReport::~ProfileReport()
   2.405 +{
   2.406 +	for (size_t i = 0; i < m_Reports.size(); i++)
   2.407 +	{
   2.408 +		delete m_Reports[i];
   2.409 +	}
   2.410 +}
   2.411 +
   2.412 +void ProfileReport::Clear()
   2.413 +{
   2.414 +	m_ReportLookup.clear();
   2.415 +	for (size_t i = 0; i < m_Reports.size(); i++)
   2.416 +	{
   2.417 +		delete m_Reports[i];
   2.418 +	}
   2.419 +	m_Reports.clear();
   2.420 +}
   2.421 +
   2.422 +size_t ProfileReport::GetNumReports()
   2.423 +{
   2.424 +	return m_Reports.size();
   2.425 +}
   2.426 +
   2.427 +prof_atom_report_t *ProfileReport::GetReport(size_t i)
   2.428 +{
   2.429 +	return m_Reports[i];
   2.430 +}
   2.431 +
   2.432 +void ProfileReport::SaveAtom(const prof_atom_t &atom)
   2.433 +{
   2.434 +	double atom_time;
   2.435 +	char full_name[256];
   2.436 +	prof_atom_report_t **pReport, *report;
   2.437 +
   2.438 +	if (atom.atom_type == SP_PROF_NATIVES)
   2.439 +	{
   2.440 +		strncopy(full_name, atom.name, sizeof(full_name));
   2.441 +	}
   2.442 +	else
   2.443 +	{
   2.444 +		CPlugin *pl;
   2.445 +		const char *file;
   2.446 +
   2.447 +		file = "unknown";
   2.448 +		if ((pl = g_PluginSys.GetPluginByCtx(atom.ctx)) != NULL)
   2.449 +		{
   2.450 +			file = pl->GetFilename();
   2.451 +		}
   2.452 +
   2.453 +		UTIL_Format(full_name, sizeof(full_name), "%s!%s", file, atom.name);
   2.454 +	}
   2.455 +
   2.456 +	atom_time = CalcAtomTime(atom);
   2.457 +
   2.458 +	if ((pReport = m_ReportLookup.retrieve(full_name)) == NULL)
   2.459 +	{
   2.460 +		report = new prof_atom_report_t;
   2.461 +
   2.462 +		strncopy(report->atom_name, full_name, sizeof(report->atom_name));
   2.463 +		report->max_time = atom_time;
   2.464 +		report->min_time = atom_time;
   2.465 +		report->num_calls = 1;
   2.466 +		report->total_time = atom_time;
   2.467 +		
   2.468 +		m_ReportLookup.insert(full_name, report);
   2.469 +		m_Reports.push_back(report);
   2.470 +	}
   2.471 +	else
   2.472 +	{
   2.473 +		report = *pReport;
   2.474 +
   2.475 +		if (atom_time > report->max_time)
   2.476 +		{
   2.477 +			report->max_time = atom_time;
   2.478 +		}
   2.479 +		if (atom_time < report->min_time)
   2.480 +		{
   2.481 +			report->min_time = atom_time;
   2.482 +		}
   2.483 +		report->num_calls++;
   2.484 +		report->total_time += atom_time;
   2.485 +	}
   2.486 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/core/Profiler.h	Sun Mar 02 06:40:59 2008 +0000
     3.3 @@ -0,0 +1,131 @@
     3.4 +/**
     3.5 + * vim: set ts=4 :
     3.6 + * =============================================================================
     3.7 + * SourceMod
     3.8 + * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
     3.9 + * =============================================================================
    3.10 + *
    3.11 + * This program is free software; you can redistribute it and/or modify it under
    3.12 + * the terms of the GNU General Public License, version 3.0, as published by the
    3.13 + * Free Software Foundation.
    3.14 + * 
    3.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
    3.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    3.17 + * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    3.18 + * details.
    3.19 + *
    3.20 + * You should have received a copy of the GNU General Public License along with
    3.21 + * this program.  If not, see <http://www.gnu.org/licenses/>.
    3.22 + *
    3.23 + * As a special exception, AlliedModders LLC gives you permission to link the
    3.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
    3.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    3.26 + * by the Valve Corporation.  You must obey the GNU General Public License in
    3.27 + * all respects for all other code used.  Additionally, AlliedModders LLC grants
    3.28 + * this exception to all derivative works.  AlliedModders LLC defines further
    3.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    3.30 + * or <http://www.sourcemod.net/license.php>.
    3.31 + *
    3.32 + * Version: $Id$
    3.33 + */
    3.34 +
    3.35 +#ifndef _INCLUDE_SOURCEMOD_PLUGIN_PROFILER_H_
    3.36 +#define _INCLUDE_SOURCEMOD_PLUGIN_PROFILER_H_
    3.37 +
    3.38 +#include <sp_vm_api.h>
    3.39 +#include <sm_platform.h>
    3.40 +#include <sm_trie_tpl.h>
    3.41 +#include <sh_vector.h>
    3.42 +#include <sh_stack.h>
    3.43 +#include <stdio.h>
    3.44 +#include "sm_globals.h"
    3.45 +#include "sm_srvcmds.h"
    3.46 +
    3.47 +using namespace SourcePawn;
    3.48 +using namespace SourceHook;
    3.49 +
    3.50 +struct prof_point_t
    3.51 +{
    3.52 +#if defined PLATFORM_WINDOWS
    3.53 +	LARGE_INTEGER value;
    3.54 +#elif defined PLATFORM_POSIX
    3.55 +	struct timeval value;
    3.56 +#endif
    3.57 +	bool is_set;
    3.58 +};
    3.59 +
    3.60 +struct prof_atom_t
    3.61 +{
    3.62 +	int atom_type;			/* Type of object we're profiling */
    3.63 +	int atom_serial;		/* Serial number, if appropriate */
    3.64 +	sp_context_t *ctx;		/* Plugin context. */
    3.65 +	const char *name;		/* Name of the function */
    3.66 +	prof_point_t start;		/* Start time */
    3.67 +	prof_point_t end;		/* End time */
    3.68 +	double base_time;		/* Known time from children or pausing. */
    3.69 +};
    3.70 +
    3.71 +struct prof_atom_report_t
    3.72 +{
    3.73 +	char atom_name[256];	/* Full name to shove to logs */
    3.74 +	double total_time;		/* Total time spent executing, in s */
    3.75 +	unsigned int num_calls;	/* Number of invocations */
    3.76 +	double min_time;		/* Min time spent in one call, in s */
    3.77 +	double max_time;		/* Max time spent in one call, in s */
    3.78 +};
    3.79 +
    3.80 +class ProfileReport
    3.81 +{
    3.82 +public:
    3.83 +	~ProfileReport();
    3.84 +public:
    3.85 +	void SaveAtom(const prof_atom_t &atom);
    3.86 +	size_t GetNumReports();
    3.87 +	prof_atom_report_t *GetReport(size_t i);
    3.88 +	void Clear();
    3.89 +private:
    3.90 +	KTrie<prof_atom_report_t *> m_ReportLookup;
    3.91 +	CVector<prof_atom_report_t *> m_Reports;
    3.92 +};
    3.93 +
    3.94 +class ProfileEngine :
    3.95 +	public SMGlobalClass,
    3.96 +	public IRootConsoleCommand,
    3.97 +	public IProfiler
    3.98 +{
    3.99 +public:
   3.100 +	ProfileEngine();
   3.101 +public:
   3.102 +	bool IsEnabled();
   3.103 +	bool GenerateReport(FILE *fp);
   3.104 +	void Clear();
   3.105 +public: //SMGlobalClass
   3.106 +	void OnSourceModAllInitialized();
   3.107 +	void OnSourceModShutdown();
   3.108 +public: //IRootConsoleCommand
   3.109 +	void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
   3.110 +public: //IProfiler
   3.111 +	void OnNativeBegin(IPluginContext *pContext, sp_native_t *native);
   3.112 +	void OnNativeEnd() ;
   3.113 +	void OnFunctionBegin(IPluginContext *pContext, const char *name);
   3.114 +	void OnFunctionEnd();
   3.115 +	int OnCallbackBegin(IPluginContext *pContext, sp_public_t *pubfunc);
   3.116 +	void OnCallbackEnd(int serial);
   3.117 +private:
   3.118 +	void PushProfileStack(IPluginContext *ctx, int type, const char *name);
   3.119 +	void PopProfileStack(ProfileReport *reporter);
   3.120 +	void PauseParent();
   3.121 +	void ResumeParent(double addTime);
   3.122 +	void WriteReport(FILE *fp, ProfileReport *report, const char *name);
   3.123 +private:
   3.124 +	CStack<prof_atom_t> m_AtomStack;
   3.125 +	ProfileReport m_Callbacks;
   3.126 +	ProfileReport m_Functions;
   3.127 +	ProfileReport m_Natives;
   3.128 +	int m_serial;
   3.129 +	prof_point_t m_ProfStart;
   3.130 +};
   3.131 +
   3.132 +extern ProfileEngine g_Profiler;
   3.133 +
   3.134 +#endif //_INCLUDE_SOURCEMOD_PLUGIN_PROFILER_H_
     4.1 --- a/core/msvc8/sourcemod_mm.vcproj	Sat Mar 01 07:59:53 2008 +0000
     4.2 +++ b/core/msvc8/sourcemod_mm.vcproj	Sun Mar 02 06:40:59 2008 +0000
     4.3 @@ -1,7 +1,7 @@
     4.4  <?xml version="1.0" encoding="Windows-1252"?>
     4.5  <VisualStudioProject
     4.6  	ProjectType="Visual C++"
     4.7 -	Version="8,00"
     4.8 +	Version="8.00"
     4.9  	Name="sourcemod_mm"
    4.10  	ProjectGUID="{E39527CD-7CAB-4420-97CC-DA1B93B260BC}"
    4.11  	RootNamespace="sourcemod_mm"
    4.12 @@ -724,6 +724,10 @@
    4.13  				>
    4.14  			</File>
    4.15  			<File
    4.16 +				RelativePath="..\Profiler.cpp"
    4.17 +				>
    4.18 +			</File>
    4.19 +			<File
    4.20  				RelativePath="..\sm_autonatives.cpp"
    4.21  				>
    4.22  			</File>
    4.23 @@ -882,6 +886,10 @@
    4.24  				>
    4.25  			</File>
    4.26  			<File
    4.27 +				RelativePath="..\Profiler.h"
    4.28 +				>
    4.29 +			</File>
    4.30 +			<File
    4.31  				RelativePath="..\sm_autonatives.h"
    4.32  				>
    4.33  			</File>
     5.1 --- a/core/systems/PluginSys.cpp	Sat Mar 01 07:59:53 2008 +0000
     5.2 +++ b/core/systems/PluginSys.cpp	Sun Mar 02 06:40:59 2008 +0000
     5.3 @@ -982,7 +982,6 @@
     5.4  	g_LibSys.CloseDirectory(dir);
     5.5  }
     5.6  
     5.7 -//well i have discovered that gabe newell is very fat, so i wrote this comment now
     5.8  LoadRes CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool debug, PluginType type, char error[], size_t maxlength)
     5.9  {
    5.10  	if (m_LoadingLocked)
     6.1 --- a/core/vm/sp_vm_basecontext.cpp	Sat Mar 01 07:59:53 2008 +0000
     6.2 +++ b/core/vm/sp_vm_basecontext.cpp	Sun Mar 02 06:40:59 2008 +0000
     6.3 @@ -61,6 +61,12 @@
     6.4  	ctx = _ctx;
     6.5  	ctx->context = this;
     6.6  	ctx->dbreak = GlobalDebugBreak;
     6.7 +
     6.8 +	if (ctx->prof_flags != 0)
     6.9 +	{
    6.10 +		ctx->profiler = sm_profiler;
    6.11 +	}
    6.12 +
    6.13  	m_InExec = false;
    6.14  	m_CustomMsg = false;
    6.15  	m_funcsnum = ctx->vmbase->FunctionCount(ctx);
    6.16 @@ -150,7 +156,7 @@
    6.17  			{
    6.18  				continue;
    6.19  			}
    6.20 -			m_pub_funcs[i]->Set(pub->code_offs, this, pub->funcid);
    6.21 +			m_pub_funcs[i]->Set(pub->code_offs, this, pub->funcid, i);
    6.22  		}
    6.23  	}
    6.24  
    6.25 @@ -186,9 +192,16 @@
    6.26  	{
    6.27  		return;
    6.28  	}
    6.29 +
    6.30  	ctx = _ctx;
    6.31  	ctx->context = this;
    6.32  	ctx->dbreak = GlobalDebugBreak;
    6.33 +
    6.34 +	if (ctx->prof_flags != 0)
    6.35 +	{
    6.36 +		ctx->profiler = sm_profiler;
    6.37 +	}
    6.38 +
    6.39  	RefreshFunctionCache();
    6.40  }
    6.41  
    6.42 @@ -992,10 +1005,18 @@
    6.43  		pFunc = m_pub_funcs[func_id];
    6.44  		if (!pFunc)
    6.45  		{
    6.46 -			m_pub_funcs[func_id] = new CFunction(ctx->publics[func_id].code_offs, this, ctx->publics[func_id].funcid);
    6.47 +			m_pub_funcs[func_id] = new CFunction(ctx->publics[func_id].code_offs, 
    6.48 +												 this, 
    6.49 +												 ctx->publics[func_id].funcid,
    6.50 +												 func_id);
    6.51  			pFunc = m_pub_funcs[func_id];
    6.52 -		} else if (pFunc->IsInvalidated()) {
    6.53 -			pFunc->Set(ctx->publics[func_id].code_offs, this, ctx->publics[func_id].funcid);
    6.54 +		}
    6.55 +		else if (pFunc->IsInvalidated())
    6.56 +		{
    6.57 +			pFunc->Set(ctx->publics[func_id].code_offs, 
    6.58 +				       this,
    6.59 +					   ctx->publics[func_id].funcid,
    6.60 +					   func_id);
    6.61  		}
    6.62  	} else {
    6.63  		/* :TODO: currently not used */
    6.64 @@ -1034,16 +1055,20 @@
    6.65  		GetPublicByIndex(index, &pub);
    6.66  		if (pub)
    6.67  		{
    6.68 -			m_pub_funcs[index] = new CFunction(pub->code_offs, this, pub->funcid);
    6.69 +			m_pub_funcs[index] = new CFunction(pub->code_offs, this, pub->funcid, index);
    6.70  		}
    6.71  		pFunc = m_pub_funcs[index];
    6.72 -	} else if (pFunc->IsInvalidated()) {
    6.73 +	}
    6.74 +	else if (pFunc->IsInvalidated())
    6.75 +	{
    6.76  		sp_public_t *pub = NULL;
    6.77  		GetPublicByIndex(index, &pub);
    6.78  		if (pub)
    6.79  		{
    6.80 -			pFunc->Set(pub->code_offs, this, pub->funcid);
    6.81 -		} else {
    6.82 +			pFunc->Set(pub->code_offs, this, pub->funcid, index);
    6.83 +		}
    6.84 +		else
    6.85 +		{
    6.86  			pFunc = NULL;
    6.87  		}
    6.88  	}
     7.1 --- a/core/vm/sp_vm_basecontext.h	Sat Mar 01 07:59:53 2008 +0000
     7.2 +++ b/core/vm/sp_vm_basecontext.h	Sun Mar 02 06:40:59 2008 +0000
     7.3 @@ -39,6 +39,8 @@
     7.4   * :TODO: Make functions allocate as a lump instead of individual allocations!
     7.5   */
     7.6  
     7.7 +extern IProfiler *sm_profiler;
     7.8 +
     7.9  namespace SourcePawn
    7.10  {
    7.11  	class BaseContext : 
     8.1 --- a/core/vm/sp_vm_function.cpp	Sat Mar 01 07:59:53 2008 +0000
     8.2 +++ b/core/vm/sp_vm_function.cpp	Sun Mar 02 06:40:59 2008 +0000
     8.3 @@ -32,12 +32,13 @@
     8.4  #include <stdio.h>
     8.5  #include <string.h>
     8.6  #include "sp_vm_function.h"
     8.7 +#include "sm_stringutil.h"
     8.8  
     8.9  /********************
    8.10  * FUNCTION CALLING *
    8.11  ********************/
    8.12  
    8.13 -void CFunction::Set(uint32_t code_addr, IPluginContext *plugin, funcid_t id)
    8.14 +void CFunction::Set(uint32_t code_addr, IPluginContext *plugin, funcid_t id, uint32_t pub_id)
    8.15  {
    8.16  	m_codeaddr = code_addr;
    8.17  	m_pContext = plugin;
    8.18 @@ -46,6 +47,8 @@
    8.19  	m_Invalid = false;
    8.20  	m_pCtx = plugin ? plugin->GetContext() : NULL;
    8.21  	m_FnId = id;
    8.22 +	
    8.23 +	m_pContext->GetPublicByIndex(pub_id, &m_pPublic);
    8.24  }
    8.25  
    8.26  bool CFunction::IsRunnable()
    8.27 @@ -55,17 +58,33 @@
    8.28  
    8.29  int CFunction::CallFunction(const cell_t *params, unsigned int num_params, cell_t *result)
    8.30  {
    8.31 +	int ir, serial;
    8.32 +
    8.33  	if (!IsRunnable())
    8.34  	{
    8.35  		return SP_ERROR_NOT_RUNNABLE;
    8.36  	}
    8.37  
    8.38 +	if ((m_pCtx->prof_flags & SP_PROF_CALLBACKS) == SP_PROF_CALLBACKS
    8.39 +		&& m_pPublic != NULL)
    8.40 +	{
    8.41 +		serial = m_pCtx->profiler->OnCallbackBegin(m_pContext, m_pPublic);
    8.42 +	}
    8.43 +
    8.44  	while (num_params--)
    8.45  	{
    8.46  		m_pContext->PushCell(params[num_params]);
    8.47  	}
    8.48  
    8.49 -	return m_pContext->Execute(m_codeaddr, result);
    8.50 +	ir = m_pContext->Execute(m_codeaddr, result);
    8.51 +
    8.52 +	if ((m_pCtx->prof_flags & SP_PROF_CALLBACKS) == SP_PROF_CALLBACKS
    8.53 +		&& m_pPublic != NULL)
    8.54 +	{
    8.55 +		m_pCtx->profiler->OnCallbackEnd(serial);
    8.56 +	}
    8.57 +
    8.58 +	return ir;
    8.59  }
    8.60  
    8.61  IPluginContext *CFunction::GetParentContext()
    8.62 @@ -73,7 +92,7 @@
    8.63  	return m_pContext;
    8.64  }
    8.65  
    8.66 -CFunction::CFunction(uint32_t code_addr, IPluginContext *plugin, funcid_t id) : 
    8.67 +CFunction::CFunction(uint32_t code_addr, IPluginContext *plugin, funcid_t id, uint32_t pub_id) : 
    8.68  	m_codeaddr(code_addr), m_pContext(plugin), m_curparam(0), 
    8.69  	m_errorstate(SP_ERROR_NONE), m_FnId(id)
    8.70  {
    8.71 @@ -82,6 +101,7 @@
    8.72  	{
    8.73  		m_pCtx = plugin->GetContext();
    8.74  	}
    8.75 +	m_pContext->GetPublicByIndex(pub_id, &m_pPublic);
    8.76  }
    8.77  
    8.78  int CFunction::PushCell(cell_t cell)
    8.79 @@ -319,3 +339,4 @@
    8.80  {
    8.81  	return m_FnId;
    8.82  }
    8.83 +
     9.1 --- a/core/vm/sp_vm_function.h	Sat Mar 01 07:59:53 2008 +0000
     9.2 +++ b/core/vm/sp_vm_function.h	Sun Mar 02 06:40:59 2008 +0000
     9.3 @@ -55,7 +55,10 @@
     9.4  {
     9.5  	friend class SourcePawnEngine;
     9.6  public:
     9.7 -	CFunction(uint32_t code_addr, IPluginContext *pContext, funcid_t fnid);
     9.8 +	CFunction(uint32_t code_addr,
     9.9 +			  IPluginContext *pContext, 
    9.10 +			  funcid_t fnid,
    9.11 +			  uint32_t pub_id);
    9.12  public:
    9.13  	virtual int PushCell(cell_t cell);
    9.14  	virtual int PushCellByRef(cell_t *cell, int flags);
    9.15 @@ -79,7 +82,7 @@
    9.16  	bool IsRunnable();
    9.17  	funcid_t GetFunctionID();
    9.18  public:
    9.19 -	void Set(uint32_t code_addr, IPluginContext *plugin, funcid_t fnid);
    9.20 +	void Set(uint32_t code_addr, IPluginContext *plugin, funcid_t fnid, uint32_t pub_id);
    9.21  private:
    9.22  	int _PushString(const char *string, int sz_flags, int cp_flags, size_t len);
    9.23  	inline int SetError(int err)
    9.24 @@ -98,6 +101,7 @@
    9.25  	CFunction *m_pNext;
    9.26  	bool m_Invalid;
    9.27  	funcid_t m_FnId;
    9.28 +	sp_public_t *m_pPublic;
    9.29  };
    9.30  
    9.31  #endif //_INCLUDE_SOURCEMOD_BASEFUNCTION_H_
    10.1 --- a/public/sourcepawn/sp_vm_api.h	Sat Mar 01 07:59:53 2008 +0000
    10.2 +++ b/public/sourcepawn/sp_vm_api.h	Sun Mar 02 06:40:59 2008 +0000
    10.3 @@ -41,10 +41,10 @@
    10.4  #include "sp_vm_types.h"
    10.5  
    10.6  /** SourcePawn Engine API Version */
    10.7 -#define SOURCEPAWN_ENGINE_API_VERSION	2
    10.8 +#define SOURCEPAWN_ENGINE_API_VERSION	3
    10.9  
   10.10  /** SourcePawn VM API Version */
   10.11 -#define SOURCEPAWN_VM_API_VERSION		5
   10.12 +#define SOURCEPAWN_VM_API_VERSION		6
   10.13  
   10.14  #if !defined SOURCEMOD_BUILD
   10.15  #define SOURCEMOD_BUILD
   10.16 @@ -688,6 +688,63 @@
   10.17  		virtual void OnContextExecuteError(IPluginContext *ctx, IContextTrace *error) =0;
   10.18  	};
   10.19  
   10.20 +	/**
   10.21 +	 * @brief Represents a code profiler for plugins.
   10.22 +	 */
   10.23 +	class IProfiler
   10.24 +	{
   10.25 +	public:
   10.26 +		/**
   10.27 +		 * @brief Invoked by the JIT to notify that a native is being started.
   10.28 +		 *
   10.29 +		 * @param pContext			Plugin context.
   10.30 +		 * @param native			Native information.
   10.31 +		 */
   10.32 +		virtual void OnNativeBegin(IPluginContext *pContext, sp_native_t *native) =0;
   10.33 +
   10.34 +		/**
   10.35 +		 * @brief Invoked by the JIT to notify that the last native on the stack 
   10.36 +		 * is no longer being executed.
   10.37 +		 */
   10.38 +		virtual void OnNativeEnd() =0;
   10.39 +
   10.40 +		/**
   10.41 +		 * @brief Invoked by the JIT to notify that a function call is starting.
   10.42 +		 *
   10.43 +		 * @param pContext			Plugin context.
   10.44 +		 * @param name				Function name, or NULL if not known.
   10.45 +		 * @param code_addr			P-Code address.
   10.46 +		 */
   10.47 +		virtual void OnFunctionBegin(IPluginContext *pContext, const char *name) =0;
   10.48 +
   10.49 +		/**
   10.50 +		 * @brief Invoked by the JIT to notify that the last function call has 
   10.51 +		 * concluded.  In the case of an error inside a function, this will not 
   10.52 +		 * be called.  Instead, the VM will call OnCallbackEnd() and the profiler 
   10.53 +		 * stack must be unwound.
   10.54 +		 */
   10.55 +		virtual void OnFunctionEnd() =0;
   10.56 +
   10.57 +		/**
   10.58 +		 * @brief Invoked by the VM to notify that a forward/callback is starting.
   10.59 +		 *
   10.60 +		 * @param pContext			Plugin context.
   10.61 +		 * @param pubfunc			Public function information.
   10.62 +		 * @return					Unique number to pass to OnFunctionEnd().
   10.63 +		 */
   10.64 +		virtual int OnCallbackBegin(IPluginContext *pContext, sp_public_t *pubfunc) =0;
   10.65 +
   10.66 +		/**
   10.67 +		 * @brief Invoked by the JIT to notify that a callback has ended.  
   10.68 +		 *
   10.69 +		 * As noted in OnFunctionEnd(), this my be called with a misaligned 
   10.70 +		 * profiler stack.  To correct this, the stack should be unwound 
   10.71 +		 * (discarding data as appropriate) to a matching serial number.
   10.72 +		 *
   10.73 +		 * @param serial			Unique number from OnCallbackBegin().
   10.74 +		 */
   10.75 +		virtual void OnCallbackEnd(int serial) =0;
   10.76 +	};
   10.77  
   10.78  	/**
   10.79  	 * @brief Contains helper functions used by VMs and the host app
    11.1 --- a/public/sourcepawn/sp_vm_types.h	Sat Mar 01 07:59:53 2008 +0000
    11.2 +++ b/public/sourcepawn/sp_vm_types.h	Sun Mar 02 06:40:59 2008 +0000
    11.3 @@ -47,6 +47,13 @@
    11.4  
    11.5  #define SP_MAX_EXEC_PARAMS				32	/**< Maximum number of parameters in a function */
    11.6  
    11.7 +#define SP_JITCONF_DEBUG		"debug"		/**< Configuration option for debugging. */
    11.8 +#define SP_JITCONF_PROFILE		"profile"	/**< Configuration option for profiling. */
    11.9 +
   11.10 +#define SP_PROF_NATIVES			(1<<0)		/**< Profile natives. */
   11.11 +#define SP_PROF_CALLBACKS		(1<<1)		/**< Profile callbacks. */
   11.12 +#define SP_PROF_FUNCTIONS		(1<<2)		/**< Profile functions. */
   11.13 +
   11.14  /**
   11.15   * @brief Error codes for SourcePawn routines.
   11.16   */
   11.17 @@ -139,6 +146,7 @@
   11.18  {
   11.19  	class IPluginContext;
   11.20  	class IVirtualMachine;
   11.21 +	class IProfiler;
   11.22  };
   11.23  
   11.24  struct sp_context_s;
   11.25 @@ -285,6 +293,8 @@
   11.26  	sp_debug_file_t	*files;		/**< Files */
   11.27  	sp_debug_line_t	*lines;		/**< Lines */
   11.28  	sp_debug_symbol_t *symbols;	/**< Symbols */
   11.29 +	SourcePawn::IProfiler *profiler;		/**< Pointer to IProfiler */
   11.30 +	uint32_t		prof_flags;	/**< Profiling flags */
   11.31  } sp_context_t;
   11.32  
   11.33  #endif //_INCLUDE_SOURCEPAWN_VM_TYPES_H
    12.1 --- a/sourcepawn/jit/x86/dll_exports.cpp	Sat Mar 01 07:59:53 2008 +0000
    12.2 +++ b/sourcepawn/jit/x86/dll_exports.cpp	Sun Mar 02 06:40:59 2008 +0000
    12.3 @@ -25,7 +25,7 @@
    12.4  {
    12.5  	engine = engine_p;
    12.6  
    12.7 -	if (api_version > SOURCEPAWN_ENGINE_API_VERSION)
    12.8 +	if (api_version > SOURCEPAWN_ENGINE_API_VERSION || api_version < 2)
    12.9  	{
   12.10  		return SP_ERROR_PARAM;
   12.11  	}
    13.1 --- a/sourcepawn/jit/x86/jit_x86.cpp	Sat Mar 01 07:59:53 2008 +0000
    13.2 +++ b/sourcepawn/jit/x86/jit_x86.cpp	Sun Mar 02 06:40:59 2008 +0000
    13.3 @@ -1278,12 +1278,95 @@
    13.4  	IA32_Return(jit);
    13.5  }
    13.6  
    13.7 +void ProfCallGate_Begin(sp_context_t *ctx, const char *name)
    13.8 +{
    13.9 +	ctx->profiler->OnFunctionBegin(ctx->context, name);
   13.10 +}
   13.11 +
   13.12 +void ProfCallGate_End(sp_context_t *ctx)
   13.13 +{
   13.14 +	ctx->profiler->OnFunctionEnd();
   13.15 +}
   13.16 +
   13.17 +const char *find_func_name(sp_plugin_t *plugin, uint32_t offs)
   13.18 +{
   13.19 +	uint32_t max, iter;
   13.20 +	sp_fdbg_symbol_t *sym;
   13.21 +	sp_fdbg_arraydim_t *arr;
   13.22 +	uint8_t *cursor = (uint8_t *)(plugin->debug.symbols);
   13.23 +
   13.24 +	max = plugin->debug.syms_num;
   13.25 +	for (iter = 0; iter < max; iter++)
   13.26 +	{
   13.27 +		sym = (sp_fdbg_symbol_t *)cursor;
   13.28 +
   13.29 +		if (sym->ident == SP_SYM_FUNCTION
   13.30 +			&& sym->codestart <= offs 
   13.31 +			&& sym->codeend > offs)
   13.32 +		{
   13.33 +			return plugin->debug.stringbase + sym->name;
   13.34 +		}
   13.35 +
   13.36 +		if (sym->dimcount > 0)
   13.37 +		{
   13.38 +			cursor += sizeof(sp_fdbg_symbol_t);
   13.39 +			arr = (sp_fdbg_arraydim_t *)cursor;
   13.40 +			cursor += sizeof(sp_fdbg_arraydim_t) * sym->dimcount;
   13.41 +			continue;
   13.42 +		}
   13.43 +
   13.44 +		cursor += sizeof(sp_fdbg_symbol_t);
   13.45 +	}
   13.46 +
   13.47 +	return NULL;
   13.48 +}
   13.49 +
   13.50  inline void WriteOp_Call(JitWriter *jit)
   13.51  {
   13.52 -	cell_t offs = jit->read_cell();
   13.53 -
   13.54 -	jitoffs_t jmp = IA32_Call_Imm32(jit, 0);
   13.55 -	IA32_Write_Jump32(jit, jmp, RelocLookup(jit, offs, false));
   13.56 +	cell_t offs;
   13.57 +	jitoffs_t jmp;
   13.58 +	CompData *data;
   13.59 +		
   13.60 +	data = (CompData *)jit->data; 
   13.61 +	offs = jit->read_cell();
   13.62 +
   13.63 +	if ((data->profile & SP_PROF_FUNCTIONS) == SP_PROF_FUNCTIONS)
   13.64 +	{
   13.65 +		const char *name;
   13.66 +
   13.67 +		/* Find the function name */
   13.68 +		if ((name = find_func_name(data->plugin, offs)) == NULL)
   13.69 +		{
   13.70 +			name = "unknown";
   13.71 +		}
   13.72 +
   13.73 +		//push name
   13.74 +		//push [esi+context] 
   13.75 +		//call ProfCallGate_Begin
   13.76 +		//add esp, 8
   13.77 +		IA32_Push_Imm32(jit, (jit_int32_t)(intptr_t)name);
   13.78 +		IA32_Push_Rm_Disp8(jit, AMX_REG_INFO, AMX_INFO_CONTEXT);
   13.79 +		jmp = IA32_Call_Imm32(jit, 0);
   13.80 +		IA32_Write_Jump32_Abs(jit, jmp, (void *)ProfCallGate_Begin);
   13.81 +		IA32_Add_Rm_Imm8(jit, REG_ESP, 8, MOD_REG);
   13.82 +
   13.83 +		//call <addr>
   13.84 +		jmp = IA32_Call_Imm32(jit, 0);
   13.85 +		IA32_Write_Jump32(jit, jmp, RelocLookup(jit, offs, false));
   13.86 +
   13.87 +		//push [esi+context]
   13.88 +		//call ProfCallGate_End
   13.89 +		//add esp, 4
   13.90 +		IA32_Push_Rm_Disp8(jit, AMX_REG_INFO, AMX_INFO_CONTEXT);
   13.91 +		jmp = IA32_Call_Imm32(jit, 0);
   13.92 +		IA32_Write_Jump32_Abs(jit, jmp, (void *)ProfCallGate_End);
   13.93 +		IA32_Add_Rm_Imm8(jit, REG_ESP, 4, MOD_REG);
   13.94 +	}
   13.95 +	else
   13.96 +	{
   13.97 +		jmp = IA32_Call_Imm32(jit, 0);
   13.98 +		IA32_Write_Jump32(jit, jmp, RelocLookup(jit, offs, false));
   13.99 +	}
  13.100  }
  13.101  
  13.102  inline void WriteOp_Bounds(JitWriter *jit)
  13.103 @@ -1653,9 +1736,25 @@
  13.104  	jitoffs_t call = IA32_Call_Imm32(jit, 0);
  13.105  	if (!data->debug)
  13.106  	{
  13.107 -		IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback);
  13.108 -	} else {
  13.109 -		IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback_Debug);
  13.110 +		if ((data->profile & SP_PROF_NATIVES) == SP_PROF_NATIVES)
  13.111 +		{
  13.112 +			IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback_Profile);
  13.113 +		}
  13.114 +		else
  13.115 +		{
  13.116 +			IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback);
  13.117 +		}
  13.118 +	}
  13.119 +	else
  13.120 +	{
  13.121 +		if ((data->profile & SP_PROF_NATIVES) == SP_PROF_NATIVES)
  13.122 +		{
  13.123 +			IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback_Debug_Profile);
  13.124 +		}
  13.125 +		else
  13.126 +		{
  13.127 +			IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback_Debug);
  13.128 +		}
  13.129  	}
  13.130  	
  13.131  	/* check for errors */
  13.132 @@ -2122,7 +2221,9 @@
  13.133  
  13.134  cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params)
  13.135  {
  13.136 -	sp_native_t *native = &ctx->natives[native_idx];
  13.137 +	sp_native_t *native;
  13.138 +	
  13.139 +	native = &ctx->natives[native_idx];
  13.140  
  13.141  	ctx->n_idx = native_idx;
  13.142  	
  13.143 @@ -2136,12 +2237,27 @@
  13.144  	return native->pfn(ctx->context, params);
  13.145  }
  13.146  
  13.147 -static cell_t InvalidNative(IPluginContext *pCtx, const cell_t *params)
  13.148 +cell_t NativeCallback_Profile(sp_context_t *ctx, ucell_t native_idx, cell_t *params)
  13.149  {
  13.150 -	sp_context_t *ctx = pCtx->GetContext();
  13.151 -	ctx->n_err = SP_ERROR_INVALID_NATIVE;
  13.152 -
  13.153 -	return 0;
  13.154 +	cell_t val;
  13.155 +	sp_native_t *native;
  13.156 +
  13.157 +	native = &ctx->natives[native_idx];
  13.158 +
  13.159 +	ctx->n_idx = native_idx;
  13.160 +
  13.161 +	/* Technically both aren't needed, I guess */
  13.162 +	if (native->status == SP_NATIVE_UNBOUND)
  13.163 +	{
  13.164 +		ctx->n_err = SP_ERROR_INVALID_NATIVE;
  13.165 +		return 0;
  13.166 +	}
  13.167 +
  13.168 +	ctx->profiler->OnNativeBegin(ctx->context, native);
  13.169 +	val = native->pfn(ctx->context, params);
  13.170 +	ctx->profiler->OnNativeEnd();
  13.171 +
  13.172 +	return val;
  13.173  }
  13.174  
  13.175  cell_t NativeCallback_Debug(sp_context_t *ctx, ucell_t native_idx, cell_t *params)
  13.176 @@ -2170,7 +2286,7 @@
  13.177  	}
  13.178  
  13.179  	cell_t result = NativeCallback(ctx, native_idx, params);
  13.180 -	
  13.181 +
  13.182  	if (ctx->n_err != SP_ERROR_NONE)
  13.183  	{
  13.184  		return result;
  13.185 @@ -2180,7 +2296,9 @@
  13.186  	{
  13.187  		ctx->n_err = SP_ERROR_STACKLEAK;
  13.188  		return result;
  13.189 -	} else if (save_hp != ctx->hp) {
  13.190 +	}
  13.191 +	else if (save_hp != ctx->hp)
  13.192 +	{
  13.193  		ctx->n_err = SP_ERROR_HEAPLEAK;
  13.194  		return result;
  13.195  	}
  13.196 @@ -2188,6 +2306,60 @@
  13.197  	return result;
  13.198  }
  13.199  
  13.200 +cell_t NativeCallback_Debug_Profile(sp_context_t *ctx, ucell_t native_idx, cell_t *params)
  13.201 +{
  13.202 +	cell_t save_sp = ctx->sp;
  13.203 +	cell_t save_hp = ctx->hp;
  13.204 +
  13.205 +	ctx->n_idx = native_idx;
  13.206 +
  13.207 +	if (ctx->hp < ctx->heap_base)
  13.208 +	{
  13.209 +		ctx->n_err = SP_ERROR_HEAPMIN;
  13.210 +		return 0;
  13.211 +	}
  13.212 +
  13.213 +	if (ctx->hp + STACK_MARGIN > ctx->sp)
  13.214 +	{
  13.215 +		ctx->n_err = SP_ERROR_STACKLOW;
  13.216 +		return 0;
  13.217 +	}
  13.218 +
  13.219 +	if ((uint32_t)ctx->sp >= ctx->mem_size)
  13.220 +	{
  13.221 +		ctx->n_err = SP_ERROR_STACKMIN;
  13.222 +		return 0;
  13.223 +	}
  13.224 +
  13.225 +	cell_t result = NativeCallback_Profile(ctx, native_idx, params);
  13.226 +
  13.227 +	if (ctx->n_err != SP_ERROR_NONE)
  13.228 +	{
  13.229 +		return result;
  13.230 +	}
  13.231 +
  13.232 +	if (save_sp != ctx->sp)
  13.233 +	{
  13.234 +		ctx->n_err = SP_ERROR_STACKLEAK;
  13.235 +		return result;
  13.236 +	}
  13.237 +	else if (save_hp != ctx->hp)
  13.238 +	{
  13.239 +		ctx->n_err = SP_ERROR_HEAPLEAK;
  13.240 +		return result;
  13.241 +	}
  13.242 +
  13.243 +	return result;
  13.244 +}
  13.245 +
  13.246 +static cell_t InvalidNative(IPluginContext *pCtx, const cell_t *params)
  13.247 +{
  13.248 +	sp_context_t *ctx = pCtx->GetContext();
  13.249 +	ctx->n_err = SP_ERROR_INVALID_NATIVE;
  13.250 +
  13.251 +	return 0;
  13.252 +}
  13.253 +
  13.254  jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative)
  13.255  {
  13.256  	if (jit->outptr)
  13.257 @@ -2204,7 +2376,9 @@
  13.258  		assert(pcode_offs >= 0 && (uint32_t)pcode_offs <= data->codesize);
  13.259  		/* Do the lookup in the native dictionary. */
  13.260  		return *(jitoffs_t *)(data->rebase + pcode_offs);
  13.261 -	} else {
  13.262 +	}
  13.263 +	else
  13.264 +	{
  13.265  		return 0;
  13.266  	}
  13.267  }
  13.268 @@ -2423,6 +2597,7 @@
  13.269  	ctx->heap_base = plugin->data_size;
  13.270  	ctx->hp = ctx->heap_base;
  13.271  	ctx->sp = ctx->mem_size - sizeof(cell_t);
  13.272 +	ctx->prof_flags = data->profile;
  13.273  
  13.274  	const char *strbase = plugin->info.stringbase;
  13.275  	uint32_t max, iter;
  13.276 @@ -2726,7 +2901,7 @@
  13.277  {
  13.278  	CompData *data = (CompData *)co;
  13.279  
  13.280 -	if (strcmp(key, "debug") == 0)
  13.281 +	if (strcmp(key, SP_JITCONF_DEBUG) == 0)
  13.282  	{
  13.283  		if ((atoi(val) == 1) || !strcmp(val, "yes"))
  13.284  		{
  13.285 @@ -2741,6 +2916,18 @@
  13.286  		}
  13.287  		return true;
  13.288  	}
  13.289 +	else if (strcmp(key, SP_JITCONF_PROFILE) == 0)
  13.290 +	{
  13.291 +		data->profile = atoi(val);
  13.292 +
  13.293 +		/** Callbacks must be profiled to profile functions! */
  13.294 +		if ((data->profile & SP_PROF_FUNCTIONS) == SP_PROF_FUNCTIONS)
  13.295 +		{
  13.296 +			data->profile |= SP_PROF_CALLBACKS;
  13.297 +		}
  13.298 +
  13.299 +		return true;
  13.300 +	}
  13.301  
  13.302  	return false;
  13.303  }
    14.1 --- a/sourcepawn/jit/x86/jit_x86.h	Sat Mar 01 07:59:53 2008 +0000
    14.2 +++ b/sourcepawn/jit/x86/jit_x86.h	Sun Mar 02 06:40:59 2008 +0000
    14.3 @@ -67,13 +67,14 @@
    14.4  {
    14.5  public:
    14.6  	CompData() : plugin(NULL), 
    14.7 -		debug(false), inline_level(0), rebase(NULL),
    14.8 +		debug(false), profile(0), inline_level(0), rebase(NULL),
    14.9  		error_set(SP_ERROR_NONE), func_idx(0)
   14.10  	{
   14.11  	};
   14.12  public:
   14.13  	sp_plugin_t *plugin;			/* plugin handle */
   14.14  	bool debug;						/* whether to compile debug mode */
   14.15 +	int profile;					/* profiling flags */
   14.16  	int inline_level;				/* inline optimization level */
   14.17  	jitcode_t rebase;				/* relocation map */
   14.18  	int error_set;					/* error code to halt process */
   14.19 @@ -121,6 +122,8 @@
   14.20  
   14.21  cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params);
   14.22  cell_t NativeCallback_Debug(sp_context_t *ctx, ucell_t native_idx, cell_t *params);
   14.23 +cell_t NativeCallback_Debug_Profile(sp_context_t *ctx, ucell_t native_idx, cell_t *params);
   14.24 +cell_t NativeCallback_Profile(sp_context_t *ctx, ucell_t native_idx, cell_t *params);
   14.25  jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative=false);
   14.26  
   14.27  #define AMX_REG_PRI		REG_EAX
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/tools/profiler/csharp/Comparators.cs	Sun Mar 02 06:40:59 2008 +0000
    15.3 @@ -0,0 +1,85 @@
    15.4 +using System;
    15.5 +using System.Collections;
    15.6 +using System.Text;
    15.7 +using System.Windows.Forms;
    15.8 +
    15.9 +namespace profviewer
   15.10 +{
   15.11 +    class LIStringComparator : IComparer
   15.12 +    {
   15.13 +        private int m_col;
   15.14 +
   15.15 +        public LIStringComparator(int col)
   15.16 +        {
   15.17 +            m_col = col;
   15.18 +        }
   15.19 +
   15.20 +        public int Compare(object x, object y)
   15.21 +        {
   15.22 +            ListViewItem a = (ListViewItem)x;
   15.23 +            ListViewItem b = (ListViewItem)y;
   15.24 +
   15.25 +            return String.Compare(a.SubItems[m_col].Text, b.SubItems[m_col].Text);
   15.26 +        }
   15.27 +    }
   15.28 +
   15.29 +    class LIIntComparator : IComparer
   15.30 +    {
   15.31 +        private int m_col;
   15.32 +
   15.33 +        public LIIntComparator(int col)
   15.34 +        {
   15.35 +            m_col = col;
   15.36 +        }
   15.37 +
   15.38 +        public int Compare(object x, object y)
   15.39 +        {
   15.40 +            ListViewItem a = (ListViewItem)x;
   15.41 +            ListViewItem b = (ListViewItem)y;
   15.42 +
   15.43 +            int num1 = Int32.Parse(a.SubItems[m_col].Text);
   15.44 +            int num2 = Int32.Parse(b.SubItems[m_col].Text);
   15.45 +
   15.46 +            if (num1 > num2)
   15.47 +            {
   15.48 +                return -1;
   15.49 +            }
   15.50 +            else if (num1 < num2)
   15.51 +            {
   15.52 +                return 1;
   15.53 +            }
   15.54 +
   15.55 +            return 0;
   15.56 +        }
   15.57 +    }
   15.58 +
   15.59 +    class LIDoubleComparator : IComparer
   15.60 +    {
   15.61 +        private int m_col;
   15.62 +
   15.63 +        public LIDoubleComparator(int col)
   15.64 +        {
   15.65 +            m_col = col;
   15.66 +        }
   15.67 +
   15.68 +        public int Compare(object x, object y)
   15.69 +        {
   15.70 +            ListViewItem a = (ListViewItem)x;
   15.71 +            ListViewItem b = (ListViewItem)y;
   15.72 +
   15.73 +            double num1 = Double.Parse(a.SubItems[m_col].Text);
   15.74 +            double num2 = Double.Parse(b.SubItems[m_col].Text);
   15.75 +
   15.76 +            if (num1 > num2)
   15.77 +            {
   15.78 +                return -1;
   15.79 +            }
   15.80 +            else if (num1 < num2)
   15.81 +            {
   15.82 +                return 1;
   15.83 +            }
   15.84 +
   15.85 +            return 0;
   15.86 +        }
   15.87 +    }
   15.88 +}
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/tools/profiler/csharp/Form1.Designer.cs	Sun Mar 02 06:40:59 2008 +0000
    16.3 @@ -0,0 +1,244 @@
    16.4 +namespace profviewer
    16.5 +{
    16.6 +    partial class Main
    16.7 +    {
    16.8 +        /// <summary>
    16.9 +        /// Required designer variable.
   16.10 +        /// </summary>
   16.11 +        private System.ComponentModel.IContainer components = null;
   16.12 +
   16.13 +        /// <summary>
   16.14 +        /// Clean up any resources being used.
   16.15 +        /// </summary>
   16.16 +        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
   16.17 +        protected override void Dispose(bool disposing)
   16.18 +        {
   16.19 +            if (disposing && (components != null))
   16.20 +            {
   16.21 +                components.Dispose();
   16.22 +            }
   16.23 +            base.Dispose(disposing);
   16.24 +        }
   16.25 +
   16.26 +        #region Windows Form Designer generated code
   16.27 +
   16.28 +        /// <summary>
   16.29 +        /// Required method for Designer support - do not modify
   16.30 +        /// the contents of this method with the code editor.
   16.31 +        /// </summary>
   16.32 +        private void InitializeComponent()
   16.33 +        {
   16.34 +            this.report_list = new System.Windows.Forms.ListView();
   16.35 +            this.pr_type = new System.Windows.Forms.ColumnHeader();
   16.36 +            this.pr_name = new System.Windows.Forms.ColumnHeader();
   16.37 +            this.pr_calls = new System.Windows.Forms.ColumnHeader();
   16.38 +            this.pr_avg_time = new System.Windows.Forms.ColumnHeader();
   16.39 +            this.pr_min_time = new System.Windows.Forms.ColumnHeader();
   16.40 +            this.pr_max_time = new System.Windows.Forms.ColumnHeader();
   16.41 +            this.pr_total_time = new System.Windows.Forms.ColumnHeader();
   16.42 +            this.menuStrip1 = new System.Windows.Forms.MenuStrip();
   16.43 +            this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
   16.44 +            this.menu_file_open = new System.Windows.Forms.ToolStripMenuItem();
   16.45 +            this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator();
   16.46 +            this.menu_file_exit = new System.Windows.Forms.ToolStripMenuItem();
   16.47 +            this.label1 = new System.Windows.Forms.Label();
   16.48 +            this.report_info_starttime = new System.Windows.Forms.Label();
   16.49 +            this.label2 = new System.Windows.Forms.Label();
   16.50 +            this.report_info_duration = new System.Windows.Forms.Label();
   16.51 +            this.dialog_open = new System.Windows.Forms.OpenFileDialog();
   16.52 +            this.panel1 = new System.Windows.Forms.Panel();
   16.53 +            this.menuStrip1.SuspendLayout();
   16.54 +            this.panel1.SuspendLayout();
   16.55 +            this.SuspendLayout();
   16.56 +            // 
   16.57 +            // report_list
   16.58 +            // 
   16.59 +            this.report_list.AllowColumnReorder = true;
   16.60 +            this.report_list.AutoArrange = false;
   16.61 +            this.report_list.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
   16.62 +            this.pr_type,
   16.63 +            this.pr_name,
   16.64 +            this.pr_calls,
   16.65 +            this.pr_avg_time,
   16.66 +            this.pr_min_time,
   16.67 +            this.pr_max_time,
   16.68 +            this.pr_total_time});
   16.69 +            this.report_list.Dock = System.Windows.Forms.DockStyle.Fill;
   16.70 +            this.report_list.Location = new System.Drawing.Point(0, 24);
   16.71 +            this.report_list.MultiSelect = false;
   16.72 +            this.report_list.Name = "report_list";
   16.73 +            this.report_list.Size = new System.Drawing.Size(759, 300);
   16.74 +            this.report_list.TabIndex = 0;
   16.75 +            this.report_list.UseCompatibleStateImageBehavior = false;
   16.76 +            this.report_list.View = System.Windows.Forms.View.Details;
   16.77 +            this.report_list.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.report_list_ColumnClick);
   16.78 +            // 
   16.79 +            // pr_type
   16.80 +            // 
   16.81 +            this.pr_type.Text = "Type";
   16.82 +            this.pr_type.Width = 71;
   16.83 +            // 
   16.84 +            // pr_name
   16.85 +            // 
   16.86 +            this.pr_name.Text = "Name";
   16.87 +            this.pr_name.Width = 270;
   16.88 +            // 
   16.89 +            // pr_calls
   16.90 +            // 
   16.91 +            this.pr_calls.Text = "Calls";
   16.92 +            this.pr_calls.Width = 61;
   16.93 +            // 
   16.94 +            // pr_avg_time
   16.95 +            // 
   16.96 +            this.pr_avg_time.Text = "Avg Time";
   16.97 +            this.pr_avg_time.Width = 74;
   16.98 +            // 
   16.99 +            // pr_min_time
  16.100 +            // 
  16.101 +            this.pr_min_time.Text = "Min Time";
  16.102 +            this.pr_min_time.Width = 78;
  16.103 +            // 
  16.104 +            // pr_max_time
  16.105 +            // 
  16.106 +            this.pr_max_time.Text = "Max Time";
  16.107 +            this.pr_max_time.Width = 77;
  16.108 +            // 
  16.109 +            // pr_total_time
  16.110 +            // 
  16.111 +            this.pr_total_time.Text = "Total Time";
  16.112 +            this.pr_total_time.Width = 84;
  16.113 +            // 
  16.114 +            // menuStrip1
  16.115 +            // 
  16.116 +            this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
  16.117 +            this.fileToolStripMenuItem});
  16.118 +            this.menuStrip1.Location = new System.Drawing.Point(0, 0);
  16.119 +            this.menuStrip1.Name = "menuStrip1";
  16.120 +            this.menuStrip1.Size = new System.Drawing.Size(759, 24);
  16.121 +            this.menuStrip1.TabIndex = 1;
  16.122 +            this.menuStrip1.Text = "menuStrip1";
  16.123 +            // 
  16.124 +            // fileToolStripMenuItem
  16.125 +            // 
  16.126 +            this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
  16.127 +            this.menu_file_open,
  16.128 +            this.toolStripMenuItem1,
  16.129 +            this.menu_file_exit});
  16.130 +            this.fileToolStripMenuItem.Name = "fileToolStripMenuItem";
  16.131 +            this.fileToolStripMenuItem.Size = new System.Drawing.Size(35, 20);
  16.132 +            this.fileToolStripMenuItem.Text = "&File";
  16.133 +            // 
  16.134 +            // menu_file_open
  16.135 +            // 
  16.136 +            this.menu_file_open.Name = "menu_file_open";
  16.137 +            this.menu_file_open.Size = new System.Drawing.Size(100, 22);
  16.138 +            this.menu_file_open.Text = "&Open";
  16.139 +            this.menu_file_open.Click += new System.EventHandler(this.menu_file_open_Click);
  16.140 +            // 
  16.141 +            // toolStripMenuItem1
  16.142 +            // 
  16.143 +            this.toolStripMenuItem1.Name = "toolStripMenuItem1";
  16.144 +            this.toolStripMenuItem1.Size = new System.Drawing.Size(97, 6);
  16.145 +            // 
  16.146 +            // menu_file_exit
  16.147 +            // 
  16.148 +            this.menu_file_exit.Name = "menu_file_exit";
  16.149 +            this.menu_file_exit.Size = new System.Drawing.Size(100, 22);
  16.150 +            this.menu_file_exit.Text = "E&xit";
  16.151 +            this.menu_file_exit.Click += new System.EventHandler(this.menu_file_exit_Click);
  16.152 +            // 
  16.153 +            // label1
  16.154 +            // 
  16.155 +            this.label1.AutoSize = true;
  16.156 +            this.label1.Location = new System.Drawing.Point(3, 13);
  16.157 +            this.label1.Name = "label1";
  16.158 +            this.label1.Size = new System.Drawing.Size(76, 13);
  16.159 +            this.label1.TabIndex = 2;
  16.160 +            this.label1.Text = "Profile Started:";
  16.161 +            // 
  16.162 +            // report_info_starttime
  16.163 +            // 
  16.164 +            this.report_info_starttime.AutoSize = true;
  16.165 +            this.report_info_starttime.Location = new System.Drawing.Point(79, 13);
  16.166 +            this.report_info_starttime.Name = "report_info_starttime";
  16.167 +            this.report_info_starttime.Size = new System.Drawing.Size(0, 13);
  16.168 +            this.report_info_starttime.TabIndex = 3;
  16.169 +            // 
  16.170 +            // label2
  16.171 +            // 
  16.172 +            this.label2.AutoSize = true;
  16.173 +            this.label2.Location = new System.Drawing.Point(264, 13);
  16.174 +            this.label2.Name = "label2";
  16.175 +            this.label2.Size = new System.Drawing.Size(82, 13);
  16.176 +            this.label2.TabIndex = 4;
  16.177 +            this.label2.Text = "Profile Duration:";
  16.178 +            // 
  16.179 +            // report_info_duration
  16.180 +            // 
  16.181 +            this.report_info_duration.AutoSize = true;
  16.182 +            this.report_info_duration.Location = new System.Drawing.Point(346, 13);
  16.183 +            this.report_info_duration.Name = "report_info_duration";
  16.184 +            this.report_info_duration.Size = new System.Drawing.Size(0, 13);
  16.185 +            this.report_info_duration.TabIndex = 5;
  16.186 +            // 
  16.187 +            // dialog_open
  16.188 +            // 
  16.189 +            this.dialog_open.FileName = "openFileDialog1";
  16.190 +            this.dialog_open.Filter = "Profiler files|*.xml|All files|*.*";
  16.191 +            // 
  16.192 +            // panel1
  16.193 +            // 
  16.194 +            this.panel1.Controls.Add(this.label1);
  16.195 +            this.panel1.Controls.Add(this.report_info_duration);
  16.196 +            this.panel1.Controls.Add(this.report_info_starttime);
  16.197 +            this.panel1.Controls.Add(this.label2);
  16.198 +            this.panel1.Dock = System.Windows.Forms.DockStyle.Bottom;
  16.199 +            this.panel1.Location = new System.Drawing.Point(0, 324);
  16.200 +            this.panel1.Name = "panel1";
  16.201 +            this.panel1.Size = new System.Drawing.Size(759, 33);
  16.202 +            this.panel1.TabIndex = 6;
  16.203 +            // 
  16.204 +            // Main
  16.205 +            // 
  16.206 +            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
  16.207 +            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
  16.208 +            this.ClientSize = new System.Drawing.Size(759, 357);
  16.209 +            this.Controls.Add(this.report_list);
  16.210 +            this.Controls.Add(this.menuStrip1);
  16.211 +            this.Controls.Add(this.panel1);
  16.212 +            this.MainMenuStrip = this.menuStrip1;
  16.213 +            this.Name = "Main";
  16.214 +            this.Text = "SourceMod Profiler Report Viewer";
  16.215 +            this.menuStrip1.ResumeLayout(false);
  16.216 +            this.menuStrip1.PerformLayout();
  16.217 +            this.panel1.ResumeLayout(false);
  16.218 +            this.panel1.PerformLayout();
  16.219 +            this.ResumeLayout(false);
  16.220 +            this.PerformLayout();
  16.221 +
  16.222 +        }
  16.223 +
  16.224 +        #endregion
  16.225 +
  16.226 +        private System.Windows.Forms.ListView report_list;
  16.227 +        private System.Windows.Forms.ColumnHeader pr_type;
  16.228 +        private System.Windows.Forms.ColumnHeader pr_name;
  16.229 +        private System.Windows.Forms.ColumnHeader pr_calls;
  16.230 +        private System.Windows.Forms.ColumnHeader pr_avg_time;
  16.231 +        private System.Windows.Forms.ColumnHeader pr_min_time;
  16.232 +        private System.Windows.Forms.ColumnHeader pr_max_time;
  16.233 +        private System.Windows.Forms.ColumnHeader pr_total_time;
  16.234 +        private System.Windows.Forms.MenuStrip menuStrip1;
  16.235 +        private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem;
  16.236 +        private System.Windows.Forms.ToolStripMenuItem menu_file_open;
  16.237 +        private System.Windows.Forms.ToolStripSeparator toolStripMenuItem1;
  16.238 +        private System.Windows.Forms.ToolStripMenuItem menu_file_exit;
  16.239 +        private System.Windows.Forms.Label label1;
  16.240 +        private System.Windows.Forms.Label report_info_starttime;
  16.241 +        private System.Windows.Forms.Label label2;
  16.242 +        private System.Windows.Forms.Label report_info_duration;
  16.243 +        private System.Windows.Forms.OpenFileDialog dialog_open;
  16.244 +        private System.Windows.Forms.Panel panel1;
  16.245 +    }
  16.246 +}
  16.247 +
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/tools/profiler/csharp/Form1.cs	Sun Mar 02 06:40:59 2008 +0000
    17.3 @@ -0,0 +1,98 @@
    17.4 +using System;
    17.5 +using System.Collections.Generic;
    17.6 +using System.ComponentModel;
    17.7 +using System.Data;
    17.8 +using System.Drawing;
    17.9 +using System.Text;
   17.10 +using System.Windows.Forms;
   17.11 +
   17.12 +namespace profviewer
   17.13 +{
   17.14 +    public partial class Main : Form
   17.15 +    {
   17.16 +        private ProfileReport m_Report;
   17.17 +
   17.18 +        public Main()
   17.19 +        {
   17.20 +            InitializeComponent();
   17.21 +        }
   17.22 +
   17.23 +        private void menu_file_open_Click(object sender, EventArgs e)
   17.24 +        {
   17.25 +            DialogResult res;
   17.26 +            
   17.27 +            res = dialog_open.ShowDialog(this);
   17.28 +
   17.29 +            if (res != DialogResult.OK)
   17.30 +            {
   17.31 +                return;
   17.32 +            }
   17.33 +
   17.34 +            m_Report = null;
   17.35 +
   17.36 +            try
   17.37 +            {
   17.38 +                m_Report = new ProfileReport(dialog_open.FileName);
   17.39 +            }
   17.40 +            catch (System.Exception ex)
   17.41 +            {
   17.42 +                MessageBox.Show("Error opening or parsing file: " + ex.Message);
   17.43 +            }
   17.44 +
   17.45 +            UpdateListView();
   17.46 +        }
   17.47 +
   17.48 +        private void UpdateListView()
   17.49 +        {
   17.50 +            ProfileItem atom;
   17.51 +            ListViewItem item;
   17.52 +
   17.53 +            if (m_Report == null)
   17.54 +            {
   17.55 +                report_list.Items.Clear();
   17.56 +                report_info_duration.Text = "";
   17.57 +                report_info_starttime.Text = "";
   17.58 +                return;
   17.59 +            }
   17.60 +
   17.61 +            report_info_duration.Text = m_Report.Duration.ToString() + " seconds";
   17.62 +            report_info_starttime.Text = m_Report.StartTime.ToString();
   17.63 +
   17.64 +            for (int i = 0; i < m_Report.Count; i++)
   17.65 +            {
   17.66 +                atom = m_Report.GetItem(i);
   17.67 +                item = new ListViewItem(ProfileReport.TypeStrings[(int)atom.type]);
   17.68 +
   17.69 +                item.SubItems.Add(atom.name);
   17.70 +                item.SubItems.Add(atom.num_calls.ToString());
   17.71 +                item.SubItems.Add(atom.AverageTime.ToString("F6"));
   17.72 +                item.SubItems.Add(atom.min_time.ToString("F6"));
   17.73 +                item.SubItems.Add(atom.max_time.ToString("F6"));
   17.74 +                item.SubItems.Add(atom.total_time.ToString("F6"));
   17.75 +
   17.76 +                report_list.Items.Add(item);
   17.77 +            }
   17.78 +        }
   17.79 +
   17.80 +        private void menu_file_exit_Click(object sender, EventArgs e)
   17.81 +        {
   17.82 +            Application.Exit();
   17.83 +        }
   17.84 +
   17.85 +        private void report_list_ColumnClick(object sender, ColumnClickEventArgs e)
   17.86 +        {
   17.87 +            if (e.Column == 1)
   17.88 +            {
   17.89 +                report_list.ListViewItemSorter = new LIStringComparator(1);
   17.90 +            }
   17.91 +            else if (e.Column == 2)
   17.92 +            {
   17.93 +                report_list.ListViewItemSorter = new LIIntComparator(2);
   17.94 +            }
   17.95 +            else if (e.Column > 2)
   17.96 +            {
   17.97 +                report_list.ListViewItemSorter = new LIDoubleComparator(e.Column);
   17.98 +            }
   17.99 +        }
  17.100 +    }
  17.101 +}
  17.102 \ No newline at end of file
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/tools/profiler/csharp/Form1.resx	Sun Mar 02 06:40:59 2008 +0000
    18.3 @@ -0,0 +1,126 @@
    18.4 +<?xml version="1.0" encoding="utf-8"?>
    18.5 +<root>
    18.6 +  <!-- 
    18.7 +    Microsoft ResX Schema 
    18.8 +    
    18.9 +    Version 2.0
   18.10 +    
   18.11 +    The primary goals of this format is to allow a simple XML format 
   18.12 +    that is mostly human readable. The generation and parsing of the 
   18.13 +    various data types are done through the TypeConverter classes 
   18.14 +    associated with the data types.
   18.15 +    
   18.16 +    Example:
   18.17 +    
   18.18 +    ... ado.net/XML headers & schema ...
   18.19 +    <resheader name="resmimetype">text/microsoft-resx</resheader>
   18.20 +    <resheader name="version">2.0</resheader>
   18.21 +    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
   18.22 +    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
   18.23 +    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
   18.24 +    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
   18.25 +    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
   18.26 +        <value>[base64 mime encoded serialized .NET Framework object]</value>
   18.27 +    </data>
   18.28 +    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
   18.29 +        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
   18.30 +        <comment>This is a comment</comment>
   18.31 +    </data>
   18.32 +                
   18.33 +    There are any number of "resheader" rows that contain simple 
   18.34 +    name/value pairs.
   18.35 +    
   18.36 +    Each data row contains a name, and value. The row also contains a 
   18.37 +    type or mimetype. Type corresponds to a .NET class that support 
   18.38 +    text/value conversion through the TypeConverter architecture. 
   18.39 +    Classes that don't support this are serialized and stored with the 
   18.40 +    mimetype set.
   18.41 +    
   18.42 +    The mimetype is used for serialized objects, and tells the 
   18.43 +    ResXResourceReader how to depersist the object. This is currently not 
   18.44 +    extensible. For a given mimetype the value must be set accordingly:
   18.45 +    
   18.46 +    Note - application/x-microsoft.net.object.binary.base64 is the format 
   18.47 +    that the ResXResourceWriter will generate, however the reader can 
   18.48 +    read any of the formats listed below.
   18.49 +    
   18.50 +    mimetype: application/x-microsoft.net.object.binary.base64
   18.51 +    value   : The object must be serialized with 
   18.52 +            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
   18.53 +            : and then encoded with base64 encoding.
   18.54 +    
   18.55 +    mimetype: application/x-microsoft.net.object.soap.base64
   18.56 +    value   : The object must be serialized with 
   18.57 +            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
   18.58 +            : and then encoded with base64 encoding.
   18.59 +
   18.60 +    mimetype: application/x-microsoft.net.object.bytearray.base64
   18.61 +    value   : The object must be serialized into a byte array 
   18.62 +            : using a System.ComponentModel.TypeConverter
   18.63 +            : and then encoded with base64 encoding.
   18.64 +    -->
   18.65 +  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
   18.66 +    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
   18.67 +    <xsd:element name="root" msdata:IsDataSet="true">
   18.68 +      <xsd:complexType>
   18.69 +        <xsd:choice maxOccurs="unbounded">
   18.70 +          <xsd:element name="metadata">
   18.71 +            <xsd:complexType>
   18.72 +              <xsd:sequence>
   18.73 +                <xsd:element name="value" type="xsd:string" minOccurs="0" />
   18.74 +              </xsd:sequence>
   18.75 +              <xsd:attribute name="name" use="required" type="xsd:string" />
   18.76 +              <xsd:attribute name="type" type="xsd:string" />
   18.77 +              <xsd:attribute name="mimetype" type="xsd:string" />
   18.78 +              <xsd:attribute ref="xml:space" />
   18.79 +            </xsd:complexType>
   18.80 +          </xsd:element>
   18.81 +          <xsd:element name="assembly">
   18.82 +            <xsd:complexType>
   18.83 +              <xsd:attribute name="alias" type="xsd:string" />
   18.84 +              <xsd:attribute name="name" type="xsd:string" />
   18.85 +            </xsd:complexType>
   18.86 +          </xsd:element>
   18.87 +          <xsd:element name="data">
   18.88 +            <xsd:complexType>
   18.89 +              <xsd:sequence>
   18.90 +                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
   18.91 +                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
   18.92 +              </xsd:sequence>
   18.93 +              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
   18.94 +              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
   18.95 +              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
   18.96 +              <xsd:attribute ref="xml:space" />
   18.97 +            </xsd:complexType>
   18.98 +          </xsd:element>
   18.99 +          <xsd:element name="resheader">
  18.100 +            <xsd:complexType>
  18.101 +              <xsd:sequence>
  18.102 +                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
  18.103 +              </xsd:sequence>
  18.104 +              <xsd:attribute name="name" type="xsd:string" use="required" />
  18.105 +            </xsd:complexType>
  18.106 +          </xsd:element>
  18.107 +        </xsd:choice>
  18.108 +      </xsd:complexType>
  18.109 +    </xsd:element>
  18.110 +  </xsd:schema>
  18.111 +  <resheader name="resmimetype">
  18.112 +    <value>text/microsoft-resx</value>
  18.113 +  </resheader>
  18.114 +  <resheader name="version">
  18.115 +    <value>2.0</value>
  18.116 +  </resheader>
  18.117 +  <resheader name="reader">
  18.118 +    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  18.119 +  </resheader>
  18.120 +  <resheader name="writer">
  18.121 +    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  18.122 +  </resheader>
  18.123 +  <metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
  18.124 +    <value>17, 17</value>
  18.125 +  </metadata>
  18.126 +  <metadata name="dialog_open.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
  18.127 +    <value>126, 17</value>
  18.128 +  </metadata>
  18.129 +</root>
  18.130 \ No newline at end of file
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/tools/profiler/csharp/ProfReport.cs	Sun Mar 02 06:40:59 2008 +0000
    19.3 @@ -0,0 +1,157 @@
    19.4 +using System;
    19.5 +using System.Collections.Generic;
    19.6 +using System.Text;
    19.7 +using System.Xml;
    19.8 +
    19.9 +namespace profviewer
   19.10 +{
   19.11 +    enum ProfileType : int
   19.12 +    {
   19.13 +        ProfType_Unknown = 0,
   19.14 +        ProfType_Native,
   19.15 +        ProfType_Callback,
   19.16 +        ProfType_Function
   19.17 +    }
   19.18 +
   19.19 +    class ProfileItem
   19.20 +    {
   19.21 +        public string name;
   19.22 +        public double total_time;
   19.23 +        public uint num_calls;
   19.24 +        public double min_time;
   19.25 +        public double max_time;
   19.26 +        public ProfileType type;
   19.27 +
   19.28 +        public double AverageTime
   19.29 +        {
   19.30 +            get
   19.31 +            {
   19.32 +                return total_time / num_calls;
   19.33 +            }
   19.34 +        }
   19.35 +    }
   19.36 +
   19.37 +    class ProfileReport
   19.38 +    {
   19.39 +        public static string[] TypeStrings;
   19.40 +        private DateTime m_start_time;
   19.41 +        private double m_duration;
   19.42 +        private List<ProfileItem> m_Items;
   19.43 +
   19.44 +        public int Count
   19.45 +        {
   19.46 +            get
   19.47 +            {
   19.48 +                return m_Items.Count;
   19.49 +            }
   19.50 +        }
   19.51 +
   19.52 +        static ProfileReport()
   19.53 +        {
   19.54 +            TypeStrings = new string[4];
   19.55 +
   19.56 +            TypeStrings[0] = "unknown";
   19.57 +            TypeStrings[1] = "native";
   19.58 +            TypeStrings[2] = "callback";
   19.59 +            TypeStrings[3] = "function";
   19.60 +        }
   19.61 +
   19.62 +        public ProfileReport(string file)
   19.63 +        {
   19.64 +            bool in_profile;
   19.65 +            ProfileType type;
   19.66 +            string cur_report;
   19.67 +            XmlTextReader xml;
   19.68 +
   19.69 +            xml = new XmlTextReader(file);
   19.70 +            xml.WhitespaceHandling = WhitespaceHandling.None;
   19.71 +
   19.72 +            m_Items = new List<ProfileItem>();
   19.73 +
   19.74 +            type = ProfileType.ProfType_Unknown;
   19.75 +            in_profile = false;
   19.76 +            cur_report = null;
   19.77 +            while (xml.Read())
   19.78 +            {
   19.79 +                if (xml.NodeType == XmlNodeType.Element)
   19.80 +                {
   19.81 +                    if (xml.Name.CompareTo("profile") == 0)
   19.82 +                    {
   19.83 +                        in_profile = true;
   19.84 +                        m_duration = Double.Parse(xml.GetAttribute("uptime"));
   19.85 +                        m_start_time = new DateTime(1970, 1, 1, 0, 0, 0);
   19.86 +                        m_start_time.AddSeconds(Int32.Parse(xml.GetAttribute("time")));
   19.87 +                    }
   19.88 +                    else if (in_profile)
   19.89 +                    {
   19.90 +                        if (xml.Name.CompareTo("report") == 0)
   19.91 +                        {
   19.92 +                            cur_report = xml.GetAttribute("name");
   19.93 +                            if (cur_report.CompareTo("natives") == 0)
   19.94 +                            {
   19.95 +                                type = ProfileType.ProfType_Native;
   19.96 +                            }
   19.97 +                            else if (cur_report.CompareTo("callbacks") == 0)
   19.98 +                            {
   19.99 +                                type = ProfileType.ProfType_Callback;
  19.100 +                            }
  19.101 +                            else if (cur_report.CompareTo("functions") == 0)
  19.102 +                            {
  19.103 +                                type = ProfileType.ProfType_Function;
  19.104 +                            }
  19.105 +                            else
  19.106 +                            {
  19.107 +                                type = ProfileType.ProfType_Unknown;
  19.108 +                            }
  19.109 +                        }
  19.110 +                        else if (xml.Name.CompareTo("item") == 0 && cur_report != null)
  19.111 +                        {
  19.112 +                            ProfileItem item;
  19.113 +
  19.114 +                            item = new ProfileItem();
  19.115 +                            item.name = xml.GetAttribute("name");
  19.116 +                            item.max_time = Double.Parse(xml.GetAttribute("maxtime"));
  19.117 +                            item.min_time = Double.Parse(xml.GetAttribute("mintime"));
  19.118 +                            item.num_calls = UInt32.Parse(xml.GetAttribute("numcalls"));
  19.119 +                            item.total_time = Double.Parse(xml.GetAttribute("totaltime"));
  19.120 +                            item.type = type;
  19.121 +                            m_Items.Add(item);
  19.122 +                        }
  19.123 +                    }
  19.124 +                }
  19.125 +                else if (xml.NodeType == XmlNodeType.EndElement)
  19.126 +                {
  19.127 +                    if (xml.Name.CompareTo("profile") == 0)
  19.128 +                    {
  19.129 +                        break;
  19.130 +                    }
  19.131 +                    else if (xml.Name.CompareTo("report") == 0)
  19.132 +                    {
  19.133 +                        cur_report = null;
  19.134 +                    }
  19.135 +                }
  19.136 +            }
  19.137 +        }
  19.138 +
  19.139 +        public double Duration
  19.140 +        {
  19.141 +            get
  19.142 +            {
  19.143 +                return m_duration;
  19.144 +            }
  19.145 +        }
  19.146 +
  19.147 +        public DateTime StartTime
  19.148 +        {
  19.149 +            get
  19.150 +            {
  19.151 +                return m_start_time;
  19.152 +            }
  19.153 +        }
  19.154 +
  19.155 +        public ProfileItem GetItem(int i)
  19.156 +        {
  19.157 +            return m_Items[i];
  19.158 +        }
  19.159 +    }
  19.160 +}
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/tools/profiler/csharp/Program.cs	Sun Mar 02 06:40:59 2008 +0000
    20.3 @@ -0,0 +1,20 @@
    20.4 +using System;
    20.5 +using System.Collections.Generic;
    20.6 +using System.Windows.Forms;
    20.7 +
    20.8 +namespace profviewer
    20.9 +{
   20.10 +    static class Program
   20.11 +    {
   20.12 +        /// <summary>
   20.13 +        /// The main entry point for the application.
   20.14 +        /// </summary>
   20.15 +        [STAThread]
   20.16 +        static void Main()
   20.17 +        {
   20.18 +            Application.EnableVisualStyles();
   20.19 +            Application.SetCompatibleTextRenderingDefault(false);
   20.20 +            Application.Run(new Main());
   20.21 +        }
   20.22 +    }
   20.23 +}
   20.24 \ No newline at end of file
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/tools/profiler/csharp/profviewer.csproj	Sun Mar 02 06:40:59 2008 +0000
    21.3 @@ -0,0 +1,80 @@
    21.4 +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    21.5 +  <PropertyGroup>
    21.6 +    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    21.7 +    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    21.8 +    <ProductVersion>8.0.50727</ProductVersion>
    21.9 +    <SchemaVersion>2.0</SchemaVersion>
   21.10 +    <ProjectGuid>{1EE11F57-B933-4D06-B0E6-EAFB60ACAC73}</ProjectGuid>
   21.11 +    <OutputType>WinExe</OutputType>
   21.12 +    <AppDesignerFolder>Properties</AppDesignerFolder>
   21.13 +    <RootNamespace>profviewer</RootNamespace>
   21.14 +    <AssemblyName>profviewer</AssemblyName>
   21.15 +  </PropertyGroup>
   21.16 +  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
   21.17 +    <DebugSymbols>true</DebugSymbols>
   21.18 +    <DebugType>full</DebugType>
   21.19 +    <Optimize>false</Optimize>
   21.20 +    <OutputPath>bin\Debug\</OutputPath>
   21.21 +    <DefineConstants>DEBUG;TRACE</DefineConstants>
   21.22 +    <ErrorReport>prompt</ErrorReport>
   21.23 +    <WarningLevel>4</WarningLevel>
   21.24 +  </PropertyGroup>
   21.25 +  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
   21.26 +    <DebugType>pdbonly</DebugType>
   21.27 +    <Optimize>true</Optimize>
   21.28 +    <OutputPath>bin\Release\</OutputPath>
   21.29 +    <DefineConstants>TRACE</DefineConstants>
   21.30 +    <ErrorReport>prompt</ErrorReport>
   21.31 +    <WarningLevel>4</WarningLevel>
   21.32 +  </PropertyGroup>
   21.33 +  <ItemGroup>
   21.34 +    <Reference Include="System" />
   21.35 +    <Reference Include="System.Data" />
   21.36 +    <Reference Include="System.Deployment" />
   21.37 +    <Reference Include="System.Drawing" />
   21.38 +    <Reference Include="System.Windows.Forms" />
   21.39 +    <Reference Include="System.Xml" />
   21.40 +  </ItemGroup>
   21.41 +  <ItemGroup>
   21.42 +    <Compile Include="Comparators.cs" />
   21.43 +    <Compile Include="Form1.cs">
   21.44 +      <SubType>Form</SubType>
   21.45 +    </Compile>
   21.46 +    <Compile Include="Form1.Designer.cs">
   21.47 +      <DependentUpon>Form1.cs</DependentUpon>
   21.48 +    </Compile>
   21.49 +    <Compile Include="ProfReport.cs" />
   21.50 +    <Compile Include="Program.cs" />
   21.51 +    <Compile Include="Properties\AssemblyInfo.cs" />
   21.52 +    <EmbeddedResource Include="Form1.resx">
   21.53 +      <SubType>Designer</SubType>
   21.54 +      <DependentUpon>Form1.cs</DependentUpon>
   21.55 +    </EmbeddedResource>
   21.56 +    <EmbeddedResource Include="Properties\Resources.resx">
   21.57 +      <Generator>ResXFileCodeGenerator</Generator>
   21.58 +      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
   21.59 +      <SubType>Designer</SubType>
   21.60 +    </EmbeddedResource>
   21.61 +    <Compile Include="Properties\Resources.Designer.cs">
   21.62 +      <AutoGen>True</AutoGen>
   21.63 +      <DependentUpon>Resources.resx</DependentUpon>
   21.64 +    </Compile>
   21.65 +    <None Include="Properties\Settings.settings">
   21.66 +      <Generator>SettingsSingleFileGenerator</Generator>
   21.67 +      <LastGenOutput>Settings.Designer.cs</LastGenOutput>
   21.68 +    </None>
   21.69 +    <Compile Include="Properties\Settings.Designer.cs">
   21.70 +      <AutoGen>True</AutoGen>
   21.71 +      <DependentUpon>Settings.settings</DependentUpon>
   21.72 +      <DesignTimeSharedInput>True</DesignTimeSharedInput>
   21.73 +    </Compile>
   21.74 +  </ItemGroup>
   21.75 +  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   21.76 +  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
   21.77 +       Other similar extension points exist, see Microsoft.Common.targets.
   21.78 +  <Target Name="BeforeBuild">
   21.79 +  </Target>
   21.80 +  <Target Name="AfterBuild">
   21.81 +  </Target>
   21.82 +  -->
   21.83 +</Project>
   21.84 \ No newline at end of file
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/tools/profiler/csharp/profviewer.sln	Sun Mar 02 06:40:59 2008 +0000
    22.3 @@ -0,0 +1,20 @@
    22.4 +
    22.5 +Microsoft Visual Studio Solution File, Format Version 9.00
    22.6 +# Visual Studio 2005
    22.7 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "profviewer", "profviewer.csproj", "{1EE11F57-B933-4D06-B0E6-EAFB60ACAC73}"
    22.8 +EndProject
    22.9 +Global
   22.10 +	GlobalSection(SolutionConfigurationPlatforms) = preSolution
   22.11 +		Debug|Any CPU = Debug|Any CPU
   22.12 +		Release|Any CPU = Release|Any CPU
   22.13 +	EndGlobalSection
   22.14 +	GlobalSection(ProjectConfigurationPlatforms) = postSolution
   22.15 +		{1EE11F57-B933-4D06-B0E6-EAFB60ACAC73}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
   22.16 +		{1EE11F57-B933-4D06-B0E6-EAFB60ACAC73}.Debug|Any CPU.Build.0 = Debug|Any CPU
   22.17 +		{1EE11F57-B933-4D06-B0E6-EAFB60ACAC73}.Release|Any CPU.ActiveCfg = Release|Any CPU
   22.18 +		{1EE11F57-B933-4D06-B0E6-EAFB60ACAC73}.Release|Any CPU.Build.0 = Release|Any CPU
   22.19 +	EndGlobalSection
   22.20 +	GlobalSection(SolutionProperties) = preSolution
   22.21 +		HideSolutionNode = FALSE
   22.22 +	EndGlobalSection
   22.23 +EndGlobal
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/tools/profiler/php/ProfFileParser.class.php	Sun Mar 02 06:40:59 2008 +0000
    23.3 @@ -0,0 +1,73 @@
    23.4 +<?php
    23.5 +
    23.6 +class ProfReport
    23.7 +{
    23.8 +	public $time;
    23.9 +	public $uptime;
   23.10 +	public $items = array();
   23.11 +}
   23.12 +
   23.13 +class ProfReportParser
   23.14 +{
   23.15 +	private $report;
   23.16 +	private $curtype;
   23.17 +	public $last_error;
   23.18 +
   23.19 +	public function Parse($file)
   23.20 +	{
   23.21 +		$this->report = FALSE;
   23.22 +		$this->curtype = FALSE;
   23.23 +
   23.24 +		if (($contents = file_get_contents($file)) === FALSE)
   23.25 +		{
   23.26 +			$this->last_error = 'File not found';
   23.27 +			return FALSE;
   23.28 +		}
   23.29 +		
   23.30 +		$xml = xml_parser_create();
   23.31 +		xml_set_object($xml, $this);
   23.32 +		xml_set_element_handler($xml, 'tag_open', 'tag_close');
   23.33 +		xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, false);
   23.34 +
   23.35 +		if (!xml_parse($xml, $contents))
   23.36 +		{
   23.37 +			$this->last_error = 'Line: ' . xml_get_current_line_number($xml) . ' -- ' . xml_error_string(xml_get_error_code($xml));
   23.38 +			return FALSE;
   23.39 +		}
   23.40 +
   23.41 +		return $this->report;
   23.42 +	}
   23.43 +
   23.44 +	public function tag_open($parser, $tag, $attrs)
   23.45 +	{
   23.46 +		if ($tag == 'profile')
   23.47 +		{
   23.48 +			$this->report = new ProfReport();
   23.49 +			$this->report->time = $attrs['time'];
   23.50 +			$this->report->uptime = $attrs['uptime'];
   23.51 +		}
   23.52 +		else if ($tag == 'report')
   23.53 +		{
   23.54 +			$this->curtype = $attrs['name'];
   23.55 +		}
   23.56 +		else if ($tag == 'item')
   23.57 +		{
   23.58 +			if ($this->report === FALSE || $this->curtype === FALSE)
   23.59 +			{
   23.60 +				return;
   23.61 +			}
   23.62 +			$attrs['type'] = $this->curtype;
   23.63 +			$this->report->items[] = $attrs;
   23.64 +		}
   23.65 +	}
   23.66 +
   23.67 +	public function tag_close($parser, $tag)
   23.68 +	{
   23.69 +		if ($tag == 'report')
   23.70 +		{
   23.71 +			$this->curtype = FALSE;
   23.72 +		}
   23.73 +	}
   23.74 +}
   23.75 +
   23.76 +?>