Skip to content

Commit 8ee3da2

Browse files
author
Unreal Karaulov
authored
Added new debug feature: Performance Monitor. (#1019)
* Performance Monitor. Search big performance issues for any plugin that in debug mode. No server slow down. Output is plugin and function name, and server execution lag in ms. Output target: current amxlog file. * Adding cvar to enable perflog. Force for all plugin if amx_debug is 2. * Update cvar name * Use another clock from chrono * Fix debug check * Skip internal amxx exec * Move includes * Fix debug check in amx_ExecPerf * Tried to compile without min/max undefined
1 parent 6e8554d commit 8ee3da2

File tree

12 files changed

+88
-12
lines changed

12 files changed

+88
-12
lines changed

amxmodx/CForward.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,8 @@ cell CForward::execute(cell *params, ForwardPreparedArray *preparedArrays)
122122
#if defined BINLOG_ENABLED
123123
g_BinLog.WriteOp(BinLog_CallPubFunc, iter->pPlugin->getId(), iter->func);
124124
#endif
125-
int err = amx_Exec(amx, &retVal, iter->func);
126-
125+
126+
int err = amx_ExecPerf(amx, &retVal, iter->func);
127127
// log runtime error, if any
128128
if (err != AMX_ERR_NONE)
129129
{
@@ -327,8 +327,7 @@ cell CSPForward::execute(cell *params, ForwardPreparedArray *preparedArrays)
327327
#if defined BINLOG_ENABLED
328328
g_BinLog.WriteOp(BinLog_CallPubFunc, pPlugin->getId(), m_Func);
329329
#endif
330-
int err = amx_Exec(m_Amx, &retVal, m_Func);
331-
330+
int err = amx_ExecPerf(m_Amx, &retVal, m_Func);
332331
if (err != AMX_ERR_NONE)
333332
{
334333
//Did something else set an error?

amxmodx/amx.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@
6666
#include <windows.h>
6767
#endif
6868

69+
#include <chrono>
70+
#include <amxmodx.h>
71+
#include <CPlugin.h>
6972

7073
/* When one or more of the AMX_funcname macris are defined, we want
7174
* to compile only those functions. However, when none of these macros
@@ -4173,3 +4176,37 @@ int AMXAPI amx_GetStringOld(char *dest,const cell *source,int use_wchar)
41734176
dest[len]='\0'; /* store terminator */
41744177
return AMX_ERR_NONE;
41754178
}
4179+
4180+
int AMXAPI amx_ExecPerf(AMX* amx, cell* retval, int index)
4181+
{
4182+
CPluginMngr::CPlugin* perf_Plug = g_plugins.findPluginFast(amx);
4183+
if (amxmodx_perflog->value > 0.0f && perf_Plug && (perf_Plug->isDebug() || (int)amxmodx_debug->value == 2))
4184+
{
4185+
char perf_funcname[sNAMEMAX + 1];
4186+
perf_funcname[0] = '\0';
4187+
amx_GetPublic(perf_Plug->getAMX(), index, perf_funcname);
4188+
if (perf_funcname[0] == '\0')
4189+
sprintf(perf_funcname, "Unknown_ID%d", index);
4190+
4191+
const char* perf_plugname = perf_Plug->getName();
4192+
if (!perf_plugname || perf_plugname[0] == '\0')
4193+
perf_plugname = "Unknown_plugin";
4194+
4195+
using std::chrono::steady_clock;
4196+
using std::chrono::duration_cast;
4197+
using std::chrono::duration;
4198+
using std::chrono::microseconds;
4199+
4200+
auto t1 = steady_clock::now();
4201+
int err = amx_Exec(amx, retval, index);
4202+
4203+
auto ms_int = duration_cast<microseconds>(steady_clock::now() - t1);
4204+
auto ms_float = (float)(ms_int.count() / 1000.0f);
4205+
if (ms_float >= amxmodx_perflog->value)
4206+
{
4207+
AMXXLOG_Log("[%s] performance issue. Function %s executed more than %.*fms.", perf_plugname, perf_funcname, 1, ms_float);
4208+
}
4209+
return err;
4210+
}
4211+
return amx_Exec(amx, retval, index);
4212+
}

amxmodx/amx.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,7 @@ int AMXAPI amx_Callback(AMX *amx, cell index, cell *result, cell *params);
382382
int AMXAPI amx_CheckNatives(AMX *amx, AMX_NATIVE_FILTER nf);
383383
int AMXAPI amx_Cleanup(AMX *amx);
384384
int AMXAPI amx_Clone(AMX *amxClone, AMX *amxSource, void *data);
385+
int AMXAPI amx_ExecPerf(AMX* amx, cell* retval, int index);
385386
int AMXAPI amx_Exec(AMX *amx, cell *retval, int index);
386387
int AMXAPI amx_FindNative(AMX *amx, const char *name, int *index);
387388
int AMXAPI amx_FindPublic(AMX *amx, const char *funcname, int *index);

amxmodx/amxmodx.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3709,7 +3709,7 @@ static cell AMX_NATIVE_CALL callfunc_end(AMX *amx, cell *params)
37093709
amx_Push(pAmx, gparams[i]);
37103710
}
37113711

3712-
err = amx_Exec(pAmx, &retVal, func);
3712+
err = amx_ExecPerf(pAmx, &retVal, func);
37133713

37143714
if (err != AMX_ERR_NONE)
37153715
{

amxmodx/amxmodx.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,9 @@ extern bool g_official_mod;
196196
extern bool g_dontprecache;
197197
extern int g_srvindex;
198198
extern cvar_t* amxmodx_version;
199+
extern cvar_t* amxmodx_debug;
199200
extern cvar_t* amxmodx_language;
201+
extern cvar_t* amxmodx_perflog;
200202
extern cvar_t* hostname;
201203
extern cvar_t* mp_timelimit;
202204
extern fakecmd_t g_fakecmd;

amxmodx/debugger.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -728,7 +728,7 @@ int Handler::HandleModule(const char *module, bool isClass)
728728
m_pAmx->flags |= AMX_FLAG_PRENIT;
729729
amx_Push(m_pAmx, isClass ? 1 : 0);
730730
amx_PushString(m_pAmx, &hea_addr, &phys_addr, module, 0, 0);
731-
int err = amx_Exec(m_pAmx, &retval, m_iModFunc);
731+
int err = amx_ExecPerf(m_pAmx, &retval, m_iModFunc);
732732
amx_Release(m_pAmx, hea_addr);
733733
m_pAmx->flags &= ~AMX_FLAG_PRENIT;
734734

@@ -768,7 +768,7 @@ int Handler::HandleNative(const char *native, int index, int trap)
768768
amx_Push(m_pAmx, trap);
769769
amx_Push(m_pAmx, index);
770770
amx_PushString(m_pAmx, &hea_addr, &phys_addr, native, 0, 0);
771-
int err = amx_Exec(m_pAmx, &retval, m_iNatFunc);
771+
int err = amx_ExecPerf(m_pAmx, &retval, m_iNatFunc);
772772
if (err != AMX_ERR_NONE)
773773
{
774774
//LogError() took care of something for us.
@@ -841,7 +841,7 @@ int Handler::HandleError(const char *msg)
841841
amx_PushString(m_pAmx, &hea_addr, &phys_addr, msg, 0, 0);
842842
amx_Push(m_pAmx, pDebugger ? 1 : 0);
843843
amx_Push(m_pAmx, error);
844-
int err = amx_Exec(m_pAmx, &result, m_iErrFunc);
844+
int err = amx_ExecPerf(m_pAmx, &result, m_iErrFunc);
845845
if (err != AMX_ERR_NONE)
846846
{
847847
//handle this manually.

amxmodx/meta_api.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,14 @@ cvar_t init_amxmodx_debug = {"amx_debug", "1", FCVAR_SPONLY};
135135
cvar_t init_amxmodx_mldebug = {"amx_mldebug", "", FCVAR_SPONLY};
136136
cvar_t init_amxmodx_language = {"amx_language", "en", FCVAR_SERVER};
137137
cvar_t init_amxmodx_cl_langs = {"amx_client_languages", "1", FCVAR_SERVER};
138+
cvar_t init_amxmodx_perflog = { "amx_perflog_ms", "1.0", FCVAR_SPONLY };
139+
138140
cvar_t* amxmodx_version = NULL;
139141
cvar_t* amxmodx_modules = NULL;
142+
cvar_t* amxmodx_debug = NULL;
140143
cvar_t* amxmodx_language = NULL;
144+
cvar_t* amxmodx_perflog = NULL;
145+
141146
cvar_t* hostname = NULL;
142147
cvar_t* mp_timelimit = NULL;
143148

@@ -1627,9 +1632,12 @@ C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, m
16271632
CVAR_REGISTER(&init_amxmodx_mldebug);
16281633
CVAR_REGISTER(&init_amxmodx_language);
16291634
CVAR_REGISTER(&init_amxmodx_cl_langs);
1635+
CVAR_REGISTER(&init_amxmodx_perflog);
16301636

16311637
amxmodx_version = CVAR_GET_POINTER(init_amxmodx_version.name);
1638+
amxmodx_debug = CVAR_GET_POINTER(init_amxmodx_debug.name);
16321639
amxmodx_language = CVAR_GET_POINTER(init_amxmodx_language.name);
1640+
amxmodx_perflog = CVAR_GET_POINTER(init_amxmodx_perflog.name);
16331641

16341642
REG_SVR_COMMAND("amxx", amx_command);
16351643

amxmodx/modules.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ int load_amxscript_internal(AMX *amx, void **program, const char *filename, char
187187
bool will_be_debugged = false;
188188
tagAMX_DBG *pDbg = NULL;
189189

190-
if ((int)CVAR_GET_FLOAT("amx_debug") >= 2 || debug)
190+
if ((int)amxmodx_debug->value == 2 || debug)
191191
{
192192
if ((hdr->file_version < CUR_FILE_VERSION))
193193
{
@@ -544,7 +544,7 @@ int set_amxnatives(AMX* amx, char error[128])
544544

545545
if (amx_FindPublic(amx, "plugin_natives", &idx) == AMX_ERR_NONE)
546546
{
547-
if ((err = amx_Exec(amx, &retval, idx)) != AMX_ERR_NONE)
547+
if ((err = amx_ExecPerf(amx, &retval, idx)) != AMX_ERR_NONE)
548548
{
549549
Debugger::GenericMessage(amx, err);
550550
AMXXLOG_Log("An error occurred in plugin_natives. This is dangerous!");

amxmodx/natives.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,7 @@ int amxx_DynaCallback(int idx, AMX *amx, cell *params)
112112
pDebugger->BeginExec();
113113
}
114114

115-
err=amx_Exec(pNative->amx, &ret, pNative->func);
116-
115+
err = amx_ExecPerf(pNative->amx, &ret, pNative->func);
117116
if (err != AMX_ERR_NONE)
118117
{
119118
if (pDebugger && pDebugger->ErrorExists())

configs/amxx.cfg

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,3 +181,13 @@ amx_debug 1
181181
//
182182
// Default value: ""
183183
amx_mldebug ""
184+
185+
// Performance monitor
186+
//
187+
// If function executed more than amx_perflog_ms milliseconds
188+
// print plugin and function name to current amxmodx log file.
189+
//
190+
// Time in milliseconds
191+
// Default value: 1.0
192+
//
193+
amx_perflog_ms 1.0

0 commit comments

Comments
 (0)