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), "<", "<");
2.391 + UTIL_ReplaceAll(new_name, sizeof(new_name), ">", ">");
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 +?>