added profiler (windows only for now) and a benchmark script
--HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40920
This commit is contained in:
parent
f129a830b8
commit
63c5d05747
@ -854,6 +854,10 @@
|
|||||||
RelativePath="..\smn_player.cpp"
|
RelativePath="..\smn_player.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\smn_profiler.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\smn_sorting.cpp"
|
RelativePath="..\smn_sorting.cpp"
|
||||||
>
|
>
|
||||||
|
168
core/smn_profiler.cpp
Normal file
168
core/smn_profiler.cpp
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
/**
|
||||||
|
* vim: set ts=4 :
|
||||||
|
* ===============================================================
|
||||||
|
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
|
||||||
|
* ===============================================================
|
||||||
|
*
|
||||||
|
* This file is not open source and may not be copied without explicit
|
||||||
|
* written permission of AlliedModders LLC. This file may not be redistributed
|
||||||
|
* in whole or significant part.
|
||||||
|
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
|
||||||
|
*
|
||||||
|
* Version: $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "sm_globals.h"
|
||||||
|
#include "HandleSys.h"
|
||||||
|
|
||||||
|
//Note: Do not add this to Linux yet, i haven't done the HPET timing research (if even available)
|
||||||
|
//nonetheless we need accurate counting
|
||||||
|
#if defined PLATFORM_LINUX
|
||||||
|
#error "Not supported"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct Profiler
|
||||||
|
{
|
||||||
|
Profiler()
|
||||||
|
{
|
||||||
|
started = false;
|
||||||
|
stopped = false;
|
||||||
|
}
|
||||||
|
#if defined PLATFORM_WINDOWS
|
||||||
|
LARGE_INTEGER start;
|
||||||
|
LARGE_INTEGER end;
|
||||||
|
double freq;
|
||||||
|
#endif
|
||||||
|
bool started;
|
||||||
|
bool stopped;
|
||||||
|
};
|
||||||
|
|
||||||
|
HandleType_t g_ProfilerType = 0;
|
||||||
|
|
||||||
|
class ProfilerHelpers :
|
||||||
|
public SMGlobalClass,
|
||||||
|
public IHandleTypeDispatch
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void OnSourceModAllInitialized()
|
||||||
|
{
|
||||||
|
g_ProfilerType = g_HandleSys.CreateType("Profiler", this, 0, NULL, NULL, g_pCoreIdent, NULL);
|
||||||
|
}
|
||||||
|
void OnSourceModShutdown()
|
||||||
|
{
|
||||||
|
g_HandleSys.RemoveType(g_ProfilerType, g_pCoreIdent);
|
||||||
|
}
|
||||||
|
void OnHandleDestroy(HandleType_t type, void *object)
|
||||||
|
{
|
||||||
|
Profiler *prof = (Profiler *)object;
|
||||||
|
delete prof;
|
||||||
|
}
|
||||||
|
} s_ProfHelpers;
|
||||||
|
|
||||||
|
static cell_t CreateProfiler(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
Profiler *p = new Profiler();
|
||||||
|
|
||||||
|
#if defined PLATFORM_WINDOWS
|
||||||
|
LARGE_INTEGER qpf;
|
||||||
|
QueryPerformanceFrequency(&qpf);
|
||||||
|
p->freq = 1.0 / (double)(qpf.QuadPart);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Handle_t hndl = g_HandleSys.CreateHandle(g_ProfilerType, p, pContext->GetIdentity(), g_pCoreIdent, NULL);
|
||||||
|
if (hndl == BAD_HANDLE)
|
||||||
|
{
|
||||||
|
delete p;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hndl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell_t StartProfiling(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
Handle_t hndl = params[1];
|
||||||
|
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
|
||||||
|
HandleError err;
|
||||||
|
Profiler *prof;
|
||||||
|
|
||||||
|
if ((err = g_HandleSys.ReadHandle(hndl, g_ProfilerType, &sec, (void **)&prof))
|
||||||
|
!= HandleError_None)
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined PLATFORM_WINDOWS
|
||||||
|
QueryPerformanceCounter(&prof->start);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
prof->started = true;
|
||||||
|
prof->stopped = false;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell_t StopProfiling(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
Handle_t hndl = params[1];
|
||||||
|
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
|
||||||
|
HandleError err;
|
||||||
|
Profiler *prof;
|
||||||
|
|
||||||
|
if ((err = g_HandleSys.ReadHandle(hndl, g_ProfilerType, &sec, (void **)&prof))
|
||||||
|
!= HandleError_None)
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!prof->started)
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Profiler was never started");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined PLATFORM_WINDOWS
|
||||||
|
QueryPerformanceCounter(&prof->end);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
prof->started = false;
|
||||||
|
prof->stopped = true;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell_t GetProfilerTime(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
Handle_t hndl = params[1];
|
||||||
|
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
|
||||||
|
HandleError err;
|
||||||
|
Profiler *prof;
|
||||||
|
|
||||||
|
if ((err = g_HandleSys.ReadHandle(hndl, g_ProfilerType, &sec, (void **)&prof))
|
||||||
|
!= HandleError_None)
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!prof->stopped)
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Profiler was never stopped");
|
||||||
|
}
|
||||||
|
|
||||||
|
float fTime;
|
||||||
|
|
||||||
|
#if defined PLATFORM_WINDOWS
|
||||||
|
LONGLONG diff = prof->end.QuadPart - prof->start.QuadPart;
|
||||||
|
double seconds = diff * prof->freq;
|
||||||
|
fTime = (float)seconds;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return sp_ftoc(fTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_NATIVES(profilerNatives)
|
||||||
|
{
|
||||||
|
{"CreateProfiler", CreateProfiler},
|
||||||
|
{"GetProfilerTime", GetProfilerTime},
|
||||||
|
{"StartProfiling", StartProfiling},
|
||||||
|
{"StopProfiling", StopProfiling},
|
||||||
|
{NULL, NULL},
|
||||||
|
};
|
60
plugins/include/profiler.inc
Normal file
60
plugins/include/profiler.inc
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/**
|
||||||
|
* vim: set ts=4 :
|
||||||
|
* ===============================================================
|
||||||
|
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
|
||||||
|
* ===============================================================
|
||||||
|
*
|
||||||
|
* This file is part of the SourceMod/SourcePawn SDK. This file may only be used
|
||||||
|
* or modified under the Terms and Conditions of its License Agreement, which is found
|
||||||
|
* in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins
|
||||||
|
* may change at any time. To view the latest information, see:
|
||||||
|
* http://www.sourcemod.net/license.php
|
||||||
|
*
|
||||||
|
* Version: $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined _profiler_included
|
||||||
|
#endinput
|
||||||
|
#endif
|
||||||
|
#define _profiler_included
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ONLY AVAILABLE ON WINDOWS RIGHT NOW K.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new profile object. The Handle must be freed
|
||||||
|
* using CloseHandle().
|
||||||
|
*
|
||||||
|
* @return Handle to the profiler object.
|
||||||
|
*/
|
||||||
|
native Handle:CreateProfiler();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts profiling.
|
||||||
|
*
|
||||||
|
* @param prof Profiling object.
|
||||||
|
* @noreturn
|
||||||
|
* @error Invalid Handle.
|
||||||
|
*/
|
||||||
|
native StartProfiling(Handle:prof);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops profiling.
|
||||||
|
*
|
||||||
|
* @param prof Profiling object.
|
||||||
|
* @noreturn
|
||||||
|
* @error Invalid Handle or profiling was never started.
|
||||||
|
*/
|
||||||
|
native StopProfiling(Handle:prof);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the amount of high-precision time in seconds
|
||||||
|
* that passed during the profiler's last start/stop
|
||||||
|
* cycle.
|
||||||
|
*
|
||||||
|
* @param prof Profiling object.
|
||||||
|
* @return Time elapsed in seconds.
|
||||||
|
* @error Invalid Handle.
|
||||||
|
*/
|
||||||
|
native Float:GetProfilerTime(Handle:prof);
|
157
plugins/testsuite/benchmark.sp
Normal file
157
plugins/testsuite/benchmark.sp
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
#include <sourcemod>
|
||||||
|
#include <profiler>
|
||||||
|
|
||||||
|
public Plugin:myinfo =
|
||||||
|
{
|
||||||
|
name = "Benchmarks",
|
||||||
|
author = "AlliedModders LLC",
|
||||||
|
description = "Basic benchmarks",
|
||||||
|
version = "1.0.0.0",
|
||||||
|
url = "http://www.sourcemod.net/"
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MATH_INT_LOOPS 2000
|
||||||
|
#define MATH_FLOAT_LOOPS 2000
|
||||||
|
#define STRING_OP_LOOPS 2000
|
||||||
|
#define STRING_FMT_LOOPS 2000
|
||||||
|
#define STRING_ML_LOOPS 2000
|
||||||
|
#define STRING_RPLC_LOOPS 2000
|
||||||
|
|
||||||
|
new Float:g_dict_time
|
||||||
|
new Handle:g_Prof = INVALID_HANDLE
|
||||||
|
|
||||||
|
public OnPluginStart()
|
||||||
|
{
|
||||||
|
RegServerCmd("bench", Benchmark);
|
||||||
|
g_Prof = CreateProfiler();
|
||||||
|
StartProfiling(g_Prof);
|
||||||
|
LoadTranslations("fakedict-sourcemod.cfg");
|
||||||
|
StopProfiling(g_Prof);
|
||||||
|
g_dict_time = GetProfilerTime(g_Prof);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Action:Benchmark(args)
|
||||||
|
{
|
||||||
|
PrintToServer("dictionary time: %f seconds", g_dict_time);
|
||||||
|
StringBench();
|
||||||
|
MathBench();
|
||||||
|
return Plugin_Handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
MathBench()
|
||||||
|
{
|
||||||
|
StartProfiling(g_Prof);
|
||||||
|
new iter = MATH_INT_LOOPS;
|
||||||
|
new a, b, c;
|
||||||
|
while(iter--)
|
||||||
|
{
|
||||||
|
a = iter * 7;
|
||||||
|
b = 5 + iter;
|
||||||
|
c = 6 / (iter + 3);
|
||||||
|
a = 6 * (iter);
|
||||||
|
b = a * 185;
|
||||||
|
a = b / 25;
|
||||||
|
c = b - a + 3;
|
||||||
|
b = b*b;
|
||||||
|
a = (a + c) / (b - c);
|
||||||
|
b = 6;
|
||||||
|
c = 1;
|
||||||
|
b = a * 128 - c;
|
||||||
|
c = b * (a + 16) * b;
|
||||||
|
if (!a)
|
||||||
|
{
|
||||||
|
a = 5;
|
||||||
|
}
|
||||||
|
a = c + (28/a) - c;
|
||||||
|
}
|
||||||
|
StopProfiling(g_Prof);
|
||||||
|
PrintToServer("int benchmark: %f seconds", GetProfilerTime(g_Prof));
|
||||||
|
|
||||||
|
StartProfiling(g_Prof);
|
||||||
|
new Float:fa, Float:fb, Float:fc
|
||||||
|
new int1
|
||||||
|
iter = MATH_FLOAT_LOOPS;
|
||||||
|
while (iter--)
|
||||||
|
{
|
||||||
|
fa = iter * 0.7;
|
||||||
|
fb = 5.1 + iter;
|
||||||
|
fc = 6.1 / (float(iter) + 2.5);
|
||||||
|
fa = 6.1 * (iter);
|
||||||
|
fb = fa * 185.26;
|
||||||
|
fa = fb / 25.56;
|
||||||
|
fc = fb - a + float(3);
|
||||||
|
fb = fb*fb;
|
||||||
|
fa = (fa + fc) / (fb - fc);
|
||||||
|
fb = 6.2;
|
||||||
|
fc = float(1);
|
||||||
|
int1 = RoundToNearest(fa);
|
||||||
|
fb = fa * float(128) - int1;
|
||||||
|
fc = fb * (a + 16.85) * float(RoundToCeil(fb));
|
||||||
|
if (fa == 0.0)
|
||||||
|
{
|
||||||
|
fa = 5.0;
|
||||||
|
}
|
||||||
|
fa = fc + (float(28)/fa) - RoundToFloor(fc);
|
||||||
|
}
|
||||||
|
StopProfiling(g_Prof);
|
||||||
|
PrintToServer("float benchmark: %f seconds", GetProfilerTime(g_Prof));
|
||||||
|
}
|
||||||
|
|
||||||
|
#define KEY1 "LVWANBAGVXSXUGB"
|
||||||
|
#define KEY2 "IDYCVNWEOWNND"
|
||||||
|
#define KEY3 "UZWTRNHY"
|
||||||
|
#define KEY4 "EPRHAFCIUOIG"
|
||||||
|
#define KEY5 "RMZCVWIEY"
|
||||||
|
#define KEY6 "ZHPU"
|
||||||
|
|
||||||
|
StringBench()
|
||||||
|
{
|
||||||
|
new i = STRING_FMT_LOOPS;
|
||||||
|
new String:buffer[255];
|
||||||
|
|
||||||
|
StartProfiling(g_Prof);
|
||||||
|
new end
|
||||||
|
while (i--)
|
||||||
|
{
|
||||||
|
end = 0;
|
||||||
|
Format(buffer, sizeof(buffer), "%d", i);
|
||||||
|
Format(buffer, sizeof(buffer), "%d %s %d %f %d %-3.4s %s", i, "gaben", 30, 10.0, 20, "hello", "What a gaben");
|
||||||
|
end = Format(buffer, sizeof(buffer), "Well, that's just %-17.18s!", "what. this isn't a valid string! wait it is");
|
||||||
|
end += Format(buffer[end], sizeof(buffer)-end, "There are %d in this %d", i, end);
|
||||||
|
end += Format(buffer[end], sizeof(buffer)-end, "There are %d in this %d", i, end);
|
||||||
|
}
|
||||||
|
StopProfiling(g_Prof);
|
||||||
|
PrintToServer("format() benchmark: %f seconds", GetProfilerTime(g_Prof));
|
||||||
|
|
||||||
|
StartProfiling(g_Prof);
|
||||||
|
i = STRING_ML_LOOPS;
|
||||||
|
new String:fmtbuf[2048]; /* don't change to decl, amxmodx doesn't use it */
|
||||||
|
while (i--)
|
||||||
|
{
|
||||||
|
Format(fmtbuf, 2047, "%T %T %d %s %f %T", KEY1, LANG_SERVER, KEY2, LANG_SERVER, 50, "what the", 50.0, KEY3, LANG_SERVER);
|
||||||
|
Format(fmtbuf, 2047, "%s %T %s %T %T", "gaben", KEY4, LANG_SERVER, "what TIME is it", KEY5, LANG_SERVER, KEY6, LANG_SERVER);
|
||||||
|
}
|
||||||
|
StopProfiling(g_Prof);
|
||||||
|
PrintToServer("ml benchmark: %f seconds", GetProfilerTime(g_Prof));
|
||||||
|
|
||||||
|
StartProfiling(g_Prof);
|
||||||
|
i = STRING_OP_LOOPS;
|
||||||
|
while (i--)
|
||||||
|
{
|
||||||
|
StringToInt(fmtbuf)
|
||||||
|
}
|
||||||
|
StopProfiling(g_Prof);
|
||||||
|
PrintToServer("str benchmark: %f seconds", GetProfilerTime(g_Prof));
|
||||||
|
|
||||||
|
StartProfiling(g_Prof);
|
||||||
|
i = STRING_RPLC_LOOPS;
|
||||||
|
while (i--)
|
||||||
|
{
|
||||||
|
strcopy(fmtbuf, 2047, "This is a test string for you.");
|
||||||
|
ReplaceString(fmtbuf, sizeof(fmtbuf), " ", "ASDF")
|
||||||
|
ReplaceString(fmtbuf, sizeof(fmtbuf), "SDF", "")
|
||||||
|
ReplaceString(fmtbuf, sizeof(fmtbuf), "string", "gnirts")
|
||||||
|
}
|
||||||
|
StopProfiling(g_Prof);
|
||||||
|
PrintToServer("replace benchmark: %f seconds", GetProfilerTime(g_Prof));
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user