From 104bb6c05dc8effef9db715f0b708d4548e10010 Mon Sep 17 00:00:00 2001 From: shennetsind Date: Fri, 17 May 2013 21:47:10 -0300 Subject: ERS Report Redesign greatly enhances the ability to detect memory throughput More on it: http://hercules.ws/board/blog/1/entry-30-ers-report-update/ Signed-off-by: shennetsind --- src/common/db.c | 7 ++-- src/common/db.h | 10 ++--- src/common/ers.c | 117 ++++++++++++++++++++++++++++++++++++++++++++----------- src/common/ers.h | 6 ++- 4 files changed, 108 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/common/db.c b/src/common/db.c index 7ac9b2dc7..f2e69abbb 100644 --- a/src/common/db.c +++ b/src/common/db.c @@ -2400,10 +2400,10 @@ DBReleaser db_custom_release(DBRelease which) * @see #DBMap_impl * @see #db_fix_options(DBType,DBOptions) */ -DBMap* db_alloc(const char *file, int line, DBType type, DBOptions options, unsigned short maxlen) -{ +DBMap* db_alloc(const char *file, const char *func, int line, DBType type, DBOptions options, unsigned short maxlen) { DBMap_impl* db; unsigned int i; + char ers_name[50]; #ifdef DB_ENABLE_STATS DB_COUNTSTAT(db_alloc); @@ -2445,7 +2445,8 @@ DBMap* db_alloc(const char *file, int line, DBType type, DBOptions options, unsi db->free_max = 0; db->free_lock = 0; /* Other */ - db->nodes = ers_new(sizeof(struct dbn),"db.c::db_alloc",ERS_OPT_NONE); + snprintf(ers_name, 50, "db_alloc:nodes:%s:%s:%d",func,file,line); + db->nodes = ers_new(sizeof(struct dbn),ers_name,ERS_OPT_WAIT|ERS_OPT_FREE_NAME); db->cmp = db_default_cmp(type); db->hash = db_default_hash(type); db->release = db_default_release(type, options); diff --git a/src/common/db.h b/src/common/db.h index 4fe6a93d6..45babed78 100644 --- a/src/common/db.h +++ b/src/common/db.h @@ -653,10 +653,10 @@ struct DBMap { #define strdb_ensure(db,k,f) ( db_data2ptr((db)->ensure((db),db_str2key(k),(f))) ) // Database creation and destruction macros -#define idb_alloc(opt) db_alloc(__FILE__,__LINE__,DB_INT,(opt),sizeof(int)) -#define uidb_alloc(opt) db_alloc(__FILE__,__LINE__,DB_UINT,(opt),sizeof(unsigned int)) -#define strdb_alloc(opt,maxlen) db_alloc(__FILE__,__LINE__,DB_STRING,(opt),(maxlen)) -#define stridb_alloc(opt,maxlen) db_alloc(__FILE__,__LINE__,DB_ISTRING,(opt),(maxlen)) +#define idb_alloc(opt) db_alloc(__FILE__,__func__,__LINE__,DB_INT,(opt),sizeof(int)) +#define uidb_alloc(opt) db_alloc(__FILE__,__func__,__LINE__,DB_UINT,(opt),sizeof(unsigned int)) +#define strdb_alloc(opt,maxlen) db_alloc(__FILE__,__func__,__LINE__,DB_STRING,(opt),(maxlen)) +#define stridb_alloc(opt,maxlen) db_alloc(__FILE__,__func__,__LINE__,DB_ISTRING,(opt),(maxlen)) #define db_destroy(db) ( (db)->destroy((db),NULL) ) // Other macros #define db_clear(db) ( (db)->clear(db,NULL) ) @@ -775,7 +775,7 @@ DBReleaser db_custom_release(DBRelease which); * @see #db_default_release(DBType,DBOptions) * @see #db_fix_options(DBType,DBOptions) */ -DBMap* db_alloc(const char *file, int line, DBType type, DBOptions options, unsigned short maxlen); +DBMap* db_alloc(const char *file, const char *func, int line, DBType type, DBOptions options, unsigned short maxlen); /** * Manual cast from 'int' to the union DBKey. diff --git a/src/common/ers.c b/src/common/ers.c index 13e54b393..69b7609d6 100644 --- a/src/common/ers.c +++ b/src/common/ers.c @@ -50,11 +50,14 @@ #define ERS_BLOCK_ENTRIES 2048 + struct ers_list { struct ers_list *Next; }; +struct ers_instance_t; + typedef struct ers_cache { // Allocated object size, including ers_list size @@ -75,21 +78,23 @@ typedef struct ers_cache // Free objects count unsigned int Free; - // Used objects count + // Used blocks count unsigned int Used; - + + // Objects in-use count + unsigned int UsedObjs; + // Linked list struct ers_cache *Next, *Prev; } ers_cache_t; -typedef struct -{ +struct ers_instance_t { // Interface to ERS struct eri VTable; // Name, used for debbuging purpouses char *Name; - + // Misc options enum ERSOptions Options; @@ -98,11 +103,21 @@ typedef struct // Count of objects in use, used for detecting memory leaks unsigned int Count; -} ers_instance_t; + +#ifdef DEBUG + /* for data analysis [Ind/Hercules] */ + unsigned int Peak; + struct ers_instance_t *Next, *Prev; +#endif + +}; // Array containing a pointer for all ers_cache structures -static ers_cache_t *CacheList; +static ers_cache_t *CacheList = NULL; +#ifdef DEBUG + static struct ers_instance_t *InstanceList = NULL; +#endif static ers_cache_t *ers_find_cache(unsigned int size) { @@ -119,6 +134,7 @@ static ers_cache_t *ers_find_cache(unsigned int size) cache->Blocks = NULL; cache->Free = 0; cache->Used = 0; + cache->UsedObjs = 0; cache->Max = 0; if (CacheList == NULL) @@ -157,7 +173,7 @@ static void ers_free_cache(ers_cache_t *cache, bool remove) static void *ers_obj_alloc_entry(ERS self) { - ers_instance_t *instance = (ers_instance_t *)self; + struct ers_instance_t *instance = (struct ers_instance_t *)self; void *ret; if (instance == NULL) @@ -192,13 +208,19 @@ static void *ers_obj_alloc_entry(ERS self) } instance->Count++; + instance->Cache->UsedObjs++; + +#ifdef DEBUG + if( instance->Count > instance->Peak ) + instance->Peak = instance->Count; +#endif return ret; } static void ers_obj_free_entry(ERS self, void *entry) { - ers_instance_t *instance = (ers_instance_t *)self; + struct ers_instance_t *instance = (struct ers_instance_t *)self; struct ers_list *reuse = (struct ers_list *)((unsigned char *)entry - sizeof(struct ers_list)); if (instance == NULL) @@ -215,11 +237,12 @@ static void ers_obj_free_entry(ERS self, void *entry) reuse->Next = instance->Cache->ReuseList; instance->Cache->ReuseList = reuse; instance->Count--; + instance->Cache->UsedObjs--; } static size_t ers_obj_entry_size(ERS self) { - ers_instance_t *instance = (ers_instance_t *)self; + struct ers_instance_t *instance = (struct ers_instance_t *)self; if (instance == NULL) { @@ -232,7 +255,7 @@ static size_t ers_obj_entry_size(ERS self) static void ers_obj_destroy(ERS self) { - ers_instance_t *instance = (ers_instance_t *)self; + struct ers_instance_t *instance = (struct ers_instance_t *)self; if (instance == NULL) { @@ -247,13 +270,26 @@ static void ers_obj_destroy(ERS self) if (--instance->Cache->ReferenceCount <= 0) ers_free_cache(instance->Cache, true); +#ifdef DEBUG + if (instance->Next) + instance->Next->Prev = instance->Prev; + + if (instance->Prev) + instance->Prev->Next = instance->Next; + else + InstanceList = instance->Next; +#endif + + if( instance->Options & ERS_OPT_FREE_NAME ) + aFree(instance->Name); + aFree(instance); } ERS ers_new(uint32 size, char *name, enum ERSOptions options) { - ers_instance_t *instance; - CREATE(instance, ers_instance_t, 1); + struct ers_instance_t *instance; + CREATE(instance,struct ers_instance_t, 1); size += sizeof(struct ers_list); if (size % ERS_ALIGNED) @@ -264,29 +300,66 @@ ERS ers_new(uint32 size, char *name, enum ERSOptions options) instance->VTable.entry_size = ers_obj_entry_size; instance->VTable.destroy = ers_obj_destroy; - instance->Name = name; + instance->Name = ( options & ERS_OPT_FREE_NAME ) ? aStrdup(name) : name; instance->Options = options; instance->Cache = ers_find_cache(size); instance->Cache->ReferenceCount++; +#ifdef DEBUG + if (InstanceList == NULL) { + InstanceList = instance; + } else { + instance->Next = InstanceList; + instance->Next->Prev = instance; + InstanceList = instance; + InstanceList->Prev = NULL; + } +#endif instance->Count = 0; return &instance->VTable; } -void ers_report(void) -{ +void ers_report(void) { ers_cache_t *cache; - int i = 0; + unsigned int cache_c = 0, blocks_u = 0, blocks_a = 0, memory_b = 0, memory_t = 0; +#ifdef DEBUG + struct ers_instance_t *instance; + unsigned int instance_c = 0, instance_c_d = 0; + + for (instance = InstanceList; instance; instance = instance->Next) { + instance_c++; + if( (instance->Options & ERS_OPT_WAIT) && !instance->Count ) + continue; + instance_c_d++; + ShowMessage(CL_BOLD"[ERS Instance "CL_NORMAL""CL_WHITE"%s"CL_NORMAL""CL_BOLD" report]\n"CL_NORMAL, instance->Name); + ShowMessage("\tblock size : %u\n", instance->Cache->ObjectSize); + ShowMessage("\tblocks being used : %u\n", instance->Count); + ShowMessage("\tpeak blocks : %u\n", instance->Peak); + ShowMessage("\tmemory in use : %.2f MB\n", instance->Count == 0 ? 0. : (double)((instance->Count * instance->Cache->ObjectSize)/1024)/1024); + } +#endif + for (cache = CacheList; cache; cache = cache->Next) { - ShowMessage(CL_BOLD"[Entry manager #%u report]\n"CL_NORMAL, ++i); + cache_c++; + ShowMessage(CL_BOLD"[ERS Cache of size '"CL_NORMAL""CL_WHITE"%u"CL_NORMAL""CL_BOLD"' report]\n"CL_NORMAL, cache->ObjectSize); ShowMessage("\tinstances : %u\n", cache->ReferenceCount); - ShowMessage("\tblock array size : %u\n", cache->ObjectSize); - ShowMessage("\tallocated blocks : %u\n", cache->Free+cache->Used); - ShowMessage("\tentries being used : %u\n", cache->Used); - ShowMessage("\tunused entries : %u\n", cache->Free); + ShowMessage("\tblocks in use : %u/%u\n", cache->UsedObjs, cache->UsedObjs+cache->Free); + ShowMessage("\tblocks unused : %u\n", cache->Free); + ShowMessage("\tmemory in use : %.2f MB\n", cache->UsedObjs == 0 ? 0. : (double)((cache->UsedObjs * cache->ObjectSize)/1024)/1024); + ShowMessage("\tmemory allocated : %.2f MB\n", (cache->Free+cache->UsedObjs) == 0 ? 0. : (double)(((cache->UsedObjs+cache->Free) * cache->ObjectSize)/1024)/1024); + blocks_u += cache->UsedObjs; + blocks_a += cache->UsedObjs + cache->Free; + memory_b += cache->UsedObjs * cache->ObjectSize; + memory_t += (cache->UsedObjs+cache->Free) * cache->ObjectSize; } +#ifdef DEBUG + ShowInfo("ers_report: '"CL_WHITE"%u"CL_NORMAL"' instances in use, '"CL_WHITE"%u"CL_NORMAL"' displayed\n",instance_c,instance_c_d); +#endif + ShowInfo("ers_report: '"CL_WHITE"%u"CL_NORMAL"' caches in use\n",cache_c); + ShowInfo("ers_report: '"CL_WHITE"%u"CL_NORMAL"' blocks in use, consuming '"CL_WHITE"%.2f MB"CL_NORMAL"'\n",blocks_u,(double)((memory_b)/1024)/1024); + ShowInfo("ers_report: '"CL_WHITE"%u"CL_NORMAL"' blocks total, consuming '"CL_WHITE"%.2f MB"CL_NORMAL"' \n",blocks_a,(double)((memory_t)/1024)/1024); } void ers_force_destroy_all(void) diff --git a/src/common/ers.h b/src/common/ers.h index dc66af5ef..4871d8d50 100644 --- a/src/common/ers.h +++ b/src/common/ers.h @@ -71,8 +71,10 @@ #endif /* not ERS_ALIGN_ENTRY */ enum ERSOptions { - ERS_OPT_NONE = 0, - ERS_OPT_CLEAR = 1,/* silently clears any entries left in the manager upon destruction */ + ERS_OPT_NONE = 0x0, + ERS_OPT_CLEAR = 0x1,/* silently clears any entries left in the manager upon destruction */ + ERS_OPT_WAIT = 0x2,/* wait for entries to come in order to list! */ + ERS_OPT_FREE_NAME = 0x4,/* name is dynamic memory, and should be freed */ }; /** -- cgit v1.2.3-60-g2f50