diff --git a/core/CellArray.h b/core/CellArray.h index c9ee2831..f8925a60 100644 --- a/core/CellArray.h +++ b/core/CellArray.h @@ -156,6 +156,11 @@ public: return m_Data; } + size_t mem_usage() + { + return m_AllocSize * m_BlockSize * sizeof(cell_t); + } + private: bool GrowIfNeeded(size_t count) { diff --git a/core/ConVarManager.cpp b/core/ConVarManager.cpp index 594ccfd8..f245efff 100644 --- a/core/ConVarManager.cpp +++ b/core/ConVarManager.cpp @@ -241,6 +241,12 @@ void ConVarManager::OnHandleDestroy(HandleType_t type, void *object) { } +bool ConVarManager::GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize) +{ + *pSize = sizeof(ConVar); + return true; +} + void ConVarManager::OnRootConsoleCommand(const char *cmdname, const CCommand &command) { int argcount = command.ArgC(); diff --git a/core/ConVarManager.h b/core/ConVarManager.h index d9cfea24..6757bbde 100644 --- a/core/ConVarManager.h +++ b/core/ConVarManager.h @@ -82,6 +82,7 @@ public: // SMGlobalClass void OnSourceModVSPReceived(); public: // IHandleTypeDispatch void OnHandleDestroy(HandleType_t type, void *object); + bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize); public: // IPluginsListener void OnPluginUnloaded(IPlugin *plugin); public: //IRootConsoleCommand diff --git a/core/MenuManager.cpp b/core/MenuManager.cpp index e0846f5e..c68fe454 100644 --- a/core/MenuManager.cpp +++ b/core/MenuManager.cpp @@ -81,11 +81,29 @@ void MenuManager::OnHandleDestroy(HandleType_t type, void *object) { IBaseMenu *menu = (IBaseMenu *)object; menu->Destroy(false); - } else if (type == m_StyleType) { + } + else if (type == m_StyleType) + { /* Do nothing */ } } +bool MenuManager::GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize) +{ + if (type == m_MenuType) + { + *pSize = ((IBaseMenu *)object)->GetApproxMemUsage(); + return true; + } + else + { + *pSize = ((IMenuStyle *)object)->GetApproxMemUsage(); + return true; + } + + return false; +} + Handle_t MenuManager::CreateMenuHandle(IBaseMenu *menu, IdentityToken_t *pOwner) { if (m_MenuType == NO_HANDLE_TYPE) diff --git a/core/MenuManager.h b/core/MenuManager.h index 47c07360..c3f97af3 100644 --- a/core/MenuManager.h +++ b/core/MenuManager.h @@ -91,6 +91,7 @@ public: unsigned int GetRemainingVoteDelay(); public: //IHandleTypeDispatch void OnHandleDestroy(HandleType_t type, void *object); + bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize); public: HandleError ReadMenuHandle(Handle_t handle, IBaseMenu **menu); HandleError ReadStyleHandle(Handle_t handle, IMenuStyle **style); diff --git a/core/MenuStyle_Base.cpp b/core/MenuStyle_Base.cpp index fca46e6a..62f427eb 100644 --- a/core/MenuStyle_Base.cpp +++ b/core/MenuStyle_Base.cpp @@ -828,3 +828,10 @@ IMenuHandler *CBaseMenu::GetHandler() { return m_pHandler; } + +unsigned int CBaseMenu::GetBaseMemUsage() +{ + return m_Title.size() + + m_Strings.GetMemTable()->GetMemUsage() + + (m_items.size() * sizeof(CItem)); +} diff --git a/core/MenuStyle_Base.h b/core/MenuStyle_Base.h index 8d3df647..9cfe95a3 100644 --- a/core/MenuStyle_Base.h +++ b/core/MenuStyle_Base.h @@ -135,6 +135,7 @@ public: virtual unsigned int GetMenuOptionFlags(); virtual void SetMenuOptionFlags(unsigned int flags); virtual IMenuHandler *GetHandler(); + unsigned int GetBaseMemUsage(); private: void InternalDelete(); protected: diff --git a/core/MenuStyle_Radio.cpp b/core/MenuStyle_Radio.cpp index a1eee8ec..5efb3115 100644 --- a/core/MenuStyle_Radio.cpp +++ b/core/MenuStyle_Radio.cpp @@ -261,6 +261,11 @@ void CRadioStyle::ProcessWatchList() } } +unsigned int CRadioStyle::GetApproxMemUsage() +{ + return sizeof(CRadioStyle) + (sizeof(CRadioMenuPlayer) * 257); +} + CRadioDisplay::CRadioDisplay() { Reset(); @@ -494,6 +499,13 @@ bool CRadioDisplay::SetSelectableKeys(unsigned int keymap) return true; } +unsigned int CRadioDisplay::GetApproxMemUsage() +{ + return sizeof(CRadioDisplay) + + m_BufferText.size() + + m_Title.size(); +} + CRadioMenu::CRadioMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner) : CBaseMenu(pHandler, &g_RadioMenuStyle, pOwner) { @@ -542,6 +554,11 @@ void CRadioMenu::Cancel_Finally() g_RadioMenuStyle.CancelMenu(this); } +unsigned int CRadioMenu::GetApproxMemUsage() +{ + return sizeof(CRadioMenu) + GetBaseMemUsage(); +} + const char *g_RadioNumTable[11] = { "0. ", "1. ", "2. ", "3. ", "4. ", "5. ", "6. ", "7. ", "8. ", "9. ", "0. " diff --git a/core/MenuStyle_Radio.h b/core/MenuStyle_Radio.h index e8ba85f5..826c5de5 100644 --- a/core/MenuStyle_Radio.h +++ b/core/MenuStyle_Radio.h @@ -82,6 +82,7 @@ public: //IMenuStyle IMenuPanel *CreatePanel(); IBaseMenu *CreateMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner); unsigned int GetMaxPageItems(); + unsigned int GetApproxMemUsage(); public: //IUserMessageListener void OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter); void OnUserMessageSent(int msg_id); @@ -119,6 +120,7 @@ public: //IMenuPanel unsigned int GetCurrentKey(); bool SetCurrentKey(unsigned int key); int GetAmountRemaining(); + unsigned int GetApproxMemUsage(); public: void DirectSet(const char *str, int keymap); private: @@ -141,6 +143,7 @@ public: unsigned int start_item, IMenuHandler *alt_handler/* =NULL */); void Cancel_Finally(); + unsigned int GetApproxMemUsage(); }; extern CRadioStyle g_RadioMenuStyle; diff --git a/core/MenuStyle_Valve.cpp b/core/MenuStyle_Valve.cpp index dccace41..f51a85a0 100644 --- a/core/MenuStyle_Valve.cpp +++ b/core/MenuStyle_Valve.cpp @@ -163,6 +163,11 @@ bool ValveMenuStyle::DoClientMenu(int client, CBaseMenu *menu, unsigned int firs return BaseMenuStyle::DoClientMenu(client, menu, first_item, mh, time); } +unsigned int ValveMenuStyle::GetApproxMemUsage() +{ + return sizeof(ValveMenuStyle) + (sizeof(CValveMenuPlayer) * 257); +} + CValveMenuDisplay::CValveMenuDisplay() { m_pKv = NULL; @@ -342,6 +347,11 @@ int CValveMenuDisplay::GetAmountRemaining() return -1; } +unsigned int CValveMenuDisplay::GetApproxMemUsage() +{ + return sizeof(CValveMenuDisplay) + (sizeof(KeyValues) * m_NextPos * 10); +} + CValveMenu::CValveMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner) : CBaseMenu(pHandler, &g_ValveMenuStyle, pOwner), m_IntroColor(255, 0, 0, 255) @@ -409,6 +419,11 @@ void CValveMenu::SetMenuOptionFlags(unsigned int flags) CBaseMenu::SetMenuOptionFlags(flags); } +unsigned int CValveMenu::GetApproxMemUsage() +{ + return sizeof(CValveMenu) + GetBaseMemUsage(); +} + const char *g_OptionNumTable[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" diff --git a/core/MenuStyle_Valve.h b/core/MenuStyle_Valve.h index b59967c2..bf7bda4d 100644 --- a/core/MenuStyle_Valve.h +++ b/core/MenuStyle_Valve.h @@ -74,6 +74,7 @@ public: //IMenuStyle IMenuPanel *CreatePanel(); IBaseMenu *CreateMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner); unsigned int GetMaxPageItems(); + unsigned int GetApproxMemUsage(); private: void HookCreateMessage(edict_t *pEdict, DIALOG_TYPE type, KeyValues *kv, IServerPluginCallbacks *plugin); private: @@ -103,6 +104,7 @@ public: unsigned int GetCurrentKey(); bool SetCurrentKey(unsigned int key); int GetAmountRemaining(); + unsigned int GetApproxMemUsage(); private: KeyValues *m_pKv; unsigned int m_NextPos; @@ -126,6 +128,7 @@ public: //IBaseMenu unsigned int start_item, IMenuHandler *alt_handler/* =NULL */); void SetMenuOptionFlags(unsigned int flags); + unsigned int GetApproxMemUsage(); public: //CBaseMenu void Cancel_Finally(); private: diff --git a/core/sm_memtable.h b/core/sm_memtable.h index 744eb4b6..22743b7f 100644 --- a/core/sm_memtable.h +++ b/core/sm_memtable.h @@ -58,6 +58,10 @@ public: */ void Reset(); + inline unsigned int GetMemUsage() + { + return size; + } private: unsigned char *membase; diff --git a/core/sm_trie.cpp b/core/sm_trie.cpp index 14192d42..899ccd60 100644 --- a/core/sm_trie.cpp +++ b/core/sm_trie.cpp @@ -85,3 +85,8 @@ void sm_trie_clear(Trie *trie) { trie->k.clear(); } + +size_t sm_trie_mem_usage(Trie *trie) +{ + return trie->k.mem_usage(); +} diff --git a/core/sm_trie.h b/core/sm_trie.h index e3909dc2..6e25fbd1 100644 --- a/core/sm_trie.h +++ b/core/sm_trie.h @@ -41,5 +41,6 @@ bool sm_trie_replace(Trie *trie, const char *key, void *value); bool sm_trie_retrieve(Trie *trie, const char *key, void **value); bool sm_trie_delete(Trie *trie, const char *key); void sm_trie_clear(Trie *trie); +size_t sm_trie_mem_usage(Trie *trie); #endif //_INCLUDE_SOURCEMOD_SIMPLE_TRIE_H_ diff --git a/core/smn_adt_array.cpp b/core/smn_adt_array.cpp index a16fd479..cafcca54 100644 --- a/core/smn_adt_array.cpp +++ b/core/smn_adt_array.cpp @@ -56,6 +56,12 @@ public: //IHandleTypeDispatch CellArray *array = (CellArray *)object; delete array; } + bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize) + { + CellArray *pArray = (CellArray *)object; + *pSize = sizeof(CellArray) + pArray->mem_usage(); + return true; + } } s_CellArrayHelpers; static cell_t CreateArray(IPluginContext *pContext, const cell_t *params) diff --git a/core/smn_functions.cpp b/core/smn_functions.cpp index d3b0c41a..24cade1b 100644 --- a/core/smn_functions.cpp +++ b/core/smn_functions.cpp @@ -78,6 +78,12 @@ public: g_Forwards.ReleaseForward(pForward); } + + bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize) + { + *pSize = sizeof(CForward) + (((IForward *)object)->GetFunctionCount() * 12); + return true; + } } g_ForwardNativeHelpers; diff --git a/core/smn_keyvalues.cpp b/core/smn_keyvalues.cpp index 025cc5c8..c098f40d 100644 --- a/core/smn_keyvalues.cpp +++ b/core/smn_keyvalues.cpp @@ -34,6 +34,7 @@ #include "sm_stringutil.h" #include "HandleSys.h" #include +#include "utlbuffer.h" HandleType_t g_KeyValueType; @@ -63,6 +64,30 @@ public: pStk->pBase->deleteThis(); delete pStk; } + int CalcKVSizeR(KeyValues *pv) + { + CUtlBuffer buf; + int size; + + pv->RecursiveSaveToFile(buf, 0); + size = buf.TellMaxPut(); + + buf.Purge(); + + return size; + } + bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize) + { + KeyValueStack *pStk = (KeyValueStack *)object; + unsigned int size = sizeof(KeyValueStack) + (pStk->pCurRoot.size() * sizeof(KeyValues *)); + + /* Check how much memory the actual thing takes up */ + size += CalcKVSizeR(pStk->pBase); + + *pSize = size; + + return true; + } }; KeyValues *SourceModBase::ReadKeyValuesHandle(Handle_t hndl, HandleError *err, bool root) diff --git a/core/smn_menus.cpp b/core/smn_menus.cpp index 22534c7e..13473ee4 100644 --- a/core/smn_menus.cpp +++ b/core/smn_menus.cpp @@ -160,6 +160,12 @@ public: panel->DeleteThis(); } + virtual bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize) + { + *pSize = ((IMenuPanel *)object)->GetApproxMemUsage(); + return true; + } + /** * It is extremely important that unloaded plugins don't crash. * Thus, if a plugin unloads, we run through every handler we have. diff --git a/core/smn_textparse.cpp b/core/smn_textparse.cpp index 38a23e24..78b26304 100644 --- a/core/smn_textparse.cpp +++ b/core/smn_textparse.cpp @@ -169,6 +169,12 @@ public: ParseInfo *parse = (ParseInfo *)object; delete parse; } + + bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize) + { + *pSize = sizeof(ParseInfo); + return true; + } }; TextParseGlobals g_TextParseGlobals; diff --git a/core/smn_usermsgs.cpp b/core/smn_usermsgs.cpp index d560dfbe..083d333c 100644 --- a/core/smn_usermsgs.cpp +++ b/core/smn_usermsgs.cpp @@ -57,6 +57,7 @@ public: //SMGlobalClass, IHandleTypeDispatch, IPluginListener void OnSourceModAllInitialized(); void OnSourceModShutdown(); void OnHandleDestroy(HandleType_t type, void *object); + bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize); void OnPluginUnloaded(IPlugin *plugin); public: MsgListenerWrapper *CreateListener(IPluginContext *pCtx); @@ -109,6 +110,15 @@ void UsrMessageNatives::OnHandleDestroy(HandleType_t type, void *object) { } +bool UsrMessageNatives::GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize) +{ + bf_read *pRead = (bf_read *)object; + + *pSize = sizeof(bf_read) + pRead->GetNumBytesRead() + pRead->GetNumBytesLeft(); + + return true; +} + void UsrMessageNatives::OnPluginUnloaded(IPlugin *plugin) { MsgWrapperList *pList; diff --git a/core/systems/HandleSys.cpp b/core/systems/HandleSys.cpp index 5d0e9885..951e0cb9 100644 --- a/core/systems/HandleSys.cpp +++ b/core/systems/HandleSys.cpp @@ -36,6 +36,7 @@ #include "Logger.h" #include #include +#include "sm_stringutil.h" HandleSystem g_HandleSys; @@ -996,8 +997,9 @@ bool HandleSystem::TryAndFreeSomeHandles() void HandleSystem::Dump(HANDLE_REPORTER rep) { - rep("%-10.10s\t%-20.20s\t%-20.20s", "Handle", "Owner", "Type"); - rep("---------------------------------------------"); + unsigned int total_size = 0; + rep("%-10.10s\t%-20.20s\t%-20.20s\t%-10.10s", "Handle", "Owner", "Type", "Memory"); + rep("--------------------------------------------------------------------------"); for (unsigned int i = 1; i <= m_HandleTail; i++) { if (m_Handles[i].set != HandleSet_Used) @@ -1042,11 +1044,24 @@ void HandleSystem::Dump(HANDLE_REPORTER rep) } const char *type = "ANON"; QHandleType *pType = &m_Types[m_Handles[i].type]; + unsigned int size = 0; if (pType->nameIdx != -1) { type = m_strtab->GetString(pType->nameIdx); } - rep("0x%08x\t%-20.20s\t%-20.20s", index, owner, type); + if (pType->dispatch->GetDispatchVersion() < HANDLESYS_MEMUSAGE_MIN_VERSION + || !pType->dispatch->GetHandleApproxSize(m_Handles[i].type, m_Handles[i].object, &size)) + { + rep("0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, "-1"); + } + else + { + char buffer[32]; + UTIL_Format(buffer, sizeof(buffer), "%d", size); + rep("0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, buffer); + total_size += size; + } } + rep("-- Approximately %d bytes of memory are in use by Handles.\n", total_size); } diff --git a/core/systems/HandleSys.h b/core/systems/HandleSys.h index c49b1510..b76c1896 100644 --- a/core/systems/HandleSys.h +++ b/core/systems/HandleSys.h @@ -48,6 +48,8 @@ #define HANDLESYS_SERIAL_MASK 0xFFFF0000 #define HANDLESYS_HANDLE_MASK 0x0000FFFF +#define HANDLESYS_MEMUSAGE_MIN_VERSION 3 + /** * The QHandle is a nasty structure that compacts the handle system into a big vector. * The members of the vector each encapsulate one Handle, however, they also act as nodes diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index d18aa689..e8225662 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -123,6 +123,80 @@ void CPlugin::InitIdentity() } } +unsigned int CPlugin::CalcMemUsage() +{ + unsigned int base_size = + sizeof(CPlugin) + + sizeof(IdentityToken_t) + + (m_PhraseFiles.size() * sizeof(unsigned int)) + + (m_dependents.size() * sizeof(CPlugin *)) + + (m_dependsOn.size() * sizeof(CPlugin *)) + + (m_fakeNatives.size() * (sizeof(FakeNative *) + sizeof(FakeNative))) + + (m_WeakNatives.size() * sizeof(WeakNative)) + + (m_configs.size() * (sizeof(AutoConfig *) + sizeof(AutoConfig))) + + sm_trie_mem_usage(m_pProps); + + for (unsigned int i = 0; i < m_configs.size(); i++) + { + base_size += m_configs[i]->autocfg.size(); + base_size += m_configs[i]->folder.size(); + } + + for (List::iterator i = m_Libraries.begin(); + i != m_Libraries.end(); + i++) + { + base_size += (*i).size(); + } + + for (List::iterator i = m_RequiredLibs.begin(); + i != m_RequiredLibs.end(); + i++) + { + base_size += (*i).size(); + } + + for (List::iterator i = m_fakeNatives.begin(); + i != m_fakeNatives.end(); + i++) + { + base_size += (*i)->name.size(); + } + + if (m_plugin != NULL) + { + base_size += sizeof(sp_plugin_t); + base_size += m_plugin->data_size; + base_size += m_plugin->pcode_size; + base_size += (m_plugin->info.natives_num * sizeof(sp_file_natives_t)); + base_size += (m_plugin->info.publics_num * sizeof(sp_file_publics_t)); + base_size += (m_plugin->info.pubvars_num * sizeof(sp_file_pubvars_t)); + base_size += (m_plugin->debug.files_num * sizeof(sp_fdbg_file_t)); + base_size += (m_plugin->debug.lines_num * sizeof(sp_fdbg_line_t)); + base_size += (m_plugin->debug.syms_num * sizeof(sp_fdbg_symbol_t)); + /* We can't get strtab size, oh well. */ + } + + if (m_ctx.base != NULL) + { + base_size += sizeof(BaseContext); + base_size += m_ctx.base->GetPublicsNum() * sizeof(CFunction); + } + if (m_ctx.ctx != NULL) + { + base_size += m_ctx.ctx->mem_size; + base_size += (m_plugin->debug.files_num * sizeof(sp_debug_file_t)); + base_size += (m_plugin->debug.lines_num * sizeof(sp_debug_line_t)); + base_size += (m_plugin->debug.syms_num * sizeof(sp_debug_symbol_t)); + base_size += (m_plugin->info.pubvars_num * sizeof(sp_pubvar_t)); + base_size += (m_plugin->info.publics_num * sizeof(sp_public_t)); + base_size += (m_plugin->info.natives_num * sizeof(sp_native_t)); + /* We also don't know the JIT code size, oh well. */ + } + + return base_size; +} + Handle_t CPlugin::GetMyHandle() { return m_handle; @@ -1969,6 +2043,12 @@ void CPluginManager::OnHandleDestroy(HandleType_t type, void *object) /* We don't care about the internal object, actually */ } +bool CPluginManager::GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize) +{ + *pSize = ((CPlugin *)object)->CalcMemUsage(); + return true; +} + void CPluginManager::RegisterNativesFromCore(sp_nativeinfo_t *natives) { for (unsigned int i = 0; natives[i].func != NULL; i++) diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index ce70a16f..f51b0f5a 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -169,6 +169,7 @@ public: unsigned int GetSerial(); const sp_plugin_t *GetPluginStructure(); IdentityToken_t *GetIdentity(); + unsigned int CalcMemUsage(); bool SetProperty(const char *prop, void *ptr); bool GetProperty(const char *prop, void **ptr, bool remove=false); public: @@ -355,6 +356,7 @@ public: //SMGlobalClass void OnSourceModShutdown(); public: //IHandleTypeDispatch void OnHandleDestroy(HandleType_t type, void *object); + bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize); public: //IRootConsoleCommand void OnRootConsoleCommand(const char *cmdname, const CCommand &command); public: diff --git a/extensions/topmenus/TopMenu.cpp b/extensions/topmenus/TopMenu.cpp index 53b266ec..61b14620 100644 --- a/extensions/topmenus/TopMenu.cpp +++ b/extensions/topmenus/TopMenu.cpp @@ -87,6 +87,29 @@ TopMenu::~TopMenu() delete [] m_clients; } +unsigned int TopMenu::CalcMemUsage() +{ + unsigned int size = sizeof(TopMenu); + + size += m_Config.strings.GetMemTable()->MemUsage(); + size += (m_Config.cats.size() * sizeof(int)); + size += (sizeof(topmenu_player_t) * m_max_clients); + size += (m_SortedCats.size() * sizeof(unsigned int)); + size += (m_UnsortedCats.size() * sizeof(unsigned int)); + size += (m_Categories.size() * (sizeof(topmenu_category_t *) + sizeof(topmenu_category_t))); + size += (m_Objects.size() * (sizeof(topmenu_object_t *) + sizeof(topmenu_object_t))); + size += m_ObjLookup.mem_usage(); + + for (size_t i = 0; i < m_Categories.size(); i++) + { + size += m_Categories[i]->obj_list.size() * sizeof(topmenu_object_t *); + size += m_Categories[i]->sorted.size() * sizeof(topmenu_object_t *); + size += m_Categories[i]->unsorted.size() * sizeof(topmenu_object_t *); + } + + return size; +} + void TopMenu::OnClientConnected(int client) { if (m_clients == NULL) diff --git a/extensions/topmenus/TopMenu.h b/extensions/topmenus/TopMenu.h index c4c0ec86..2747c778 100644 --- a/extensions/topmenus/TopMenu.h +++ b/extensions/topmenus/TopMenu.h @@ -146,6 +146,8 @@ public: //ITextListener_SMC SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name); SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value); SMCResult ReadSMC_LeavingSection(const SMCStates *states); +public: + unsigned int CalcMemUsage(); private: void SortCategoriesIfNeeded(); void SortCategoryIfNeeded(unsigned int category); diff --git a/extensions/topmenus/sdk/sm_memtable.h b/extensions/topmenus/sdk/sm_memtable.h index 744eb4b6..7c7f00a2 100644 --- a/extensions/topmenus/sdk/sm_memtable.h +++ b/extensions/topmenus/sdk/sm_memtable.h @@ -58,6 +58,10 @@ public: */ void Reset(); + inline unsigned int MemUsage() + { + return size; + } private: unsigned char *membase; diff --git a/extensions/topmenus/smn_topmenus.cpp b/extensions/topmenus/smn_topmenus.cpp index 98575ec7..cb68c592 100644 --- a/extensions/topmenus/smn_topmenus.cpp +++ b/extensions/topmenus/smn_topmenus.cpp @@ -43,6 +43,11 @@ public: ITopMenu *pTopMenu = (ITopMenu *)object; g_TopMenus.DestroyTopMenu(pTopMenu); } + bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize) + { + *pSize = ((TopMenu *)object)->CalcMemUsage(); + return true; + } } s_TopMenuHandle; void Initialize_Natives() diff --git a/public/IHandleSys.h b/public/IHandleSys.h index 55dc5fa5..b92cf828 100644 --- a/public/IHandleSys.h +++ b/public/IHandleSys.h @@ -52,7 +52,7 @@ #include #define SMINTERFACE_HANDLESYSTEM_NAME "IHandleSys" -#define SMINTERFACE_HANDLESYSTEM_VERSION 2 +#define SMINTERFACE_HANDLESYSTEM_VERSION 3 /** Specifies no Identity */ #define DEFAULT_IDENTITY NULL @@ -195,8 +195,25 @@ namespace SourceMod public: /** * @brief Called when destroying a handle. Must be implemented. + * + * @param type Handle type. + * @param object Handle internal object. */ virtual void OnHandleDestroy(HandleType_t type, void *object) =0; + + /** + * @brief Called to get the size of a handle's memory usage in bytes. + * Implementation is optional. + * + * @param type Handle type. + * @param object Handle internal object. + * @param pSize Pointer to store the approximate memory usage in bytes. + * @return True on success, false if not implemented. + */ + virtual bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize) + { + return false; + } }; /** diff --git a/public/IMenuManager.h b/public/IMenuManager.h index cb97a2f4..16099f23 100644 --- a/public/IMenuManager.h +++ b/public/IMenuManager.h @@ -36,7 +36,7 @@ #include #define SMINTERFACE_MENUMANAGER_NAME "IMenuManager" -#define SMINTERFACE_MENUMANAGER_VERSION 13 +#define SMINTERFACE_MENUMANAGER_VERSION 14 /** * @file IMenuManager.h @@ -323,6 +323,13 @@ namespace SourceMod * -1, then the panel has no text limit. */ virtual int GetAmountRemaining() =0; + + /** + * @brief For the Handle system, returns approximate memory usage. + * + * @return Approximate number of bytes being used. + */ + virtual unsigned int GetApproxMemUsage() =0; }; /** @@ -406,6 +413,13 @@ namespace SourceMod * @return Handle_t pointing to this object. */ virtual Handle_t GetHandle() =0; + + /** + * @brief For the Handle system, returns approximate memory usage. + * + * @return Approximate number of bytes being used. + */ + virtual unsigned int GetApproxMemUsage() =0; }; /** @@ -597,6 +611,13 @@ namespace SourceMod unsigned int time, unsigned int start_item, IMenuHandler *alt_handler=NULL) =0; + + /** + * @brief For the Handle system, returns approximate memory usage. + * + * @return Approximate number of bytes being used. + */ + virtual unsigned int GetApproxMemUsage() =0; }; /** diff --git a/public/sm_trie_tpl.h b/public/sm_trie_tpl.h index 1aed1a38..195e1988 100644 --- a/public/sm_trie_tpl.h +++ b/public/sm_trie_tpl.h @@ -877,6 +877,13 @@ private: return x_check_multi(offsets, count, to_check+1); } +public: + size_t mem_usage() + { + return (sizeof(KTrieNode) * (m_baseSize)) + + m_stSize + + sizeof(KTrieNode); + } private: KTrieNode *m_base; /* Base array for the sparse tables */ KTrieNode *m_empty; /* Special case for empty strings */