You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

156 lines
4.2 KiB

/**********
Copyright 2021 The ngspice team All rights
reserved.
Author: 2021 Holger Vogt
3-clause BSD license
**********/
/* This is a test file including a local garbage collector and removal.
It might be especially useful, because cpl transmission lines have
several memory leaks during runtime in difficult to control process
sequence..
At initialization in CPLsetup() mem_init() is called setting up a hash table
to store memory addresses.
Each time TMALLOC is called, the resulting address is stored.
Each time tfree() is called, the address is removed.
For realloc(), the old address is deleted, the new one is stored,
if there is a change in the address.
Upon exiting the program, mem_delete() is called, deleting all memory
at addresses still in the hash table, then the hash table itself is removed.
CPLunsetup() calls mem_delete(). */
#include "ngspice/ngspice.h"
#include "ngspice/iferrmsg.h"
#include "ngspice/hash.h"
#include "ngspice/fteext.h"
#include "cpldefs.h"
// #define DB_FULL /* uncomment for debugging output, all addresses to files */
#ifdef DB_FULL
#define DB
#else
#define DB /* uncomment for printing some debugging output */
#endif
void mem_init(void);
void mem_delete(void);
int memsaved(void *ptr);
void memdeleted(const void *ptr);
void my_free_func(void* data);
void my_key_free(void* key);
int gc_is_on = 0;
/* add some debugging printout */
#ifdef DB
static int mem_in = 0, mem_out = 0, mem_freed = 0;
#endif
#ifdef DB_FULL
static FILE *alloclog, *freelog, *finallog;
#endif
NGHASHPTR memory_table;
/* initialize hash table to store allocated mem addresses */
void mem_init(void) {
gc_is_on = 0;
memory_table = nghash_init_pointer(1024);
gc_is_on = 1;
#ifdef DB_FULL
alloclog = fopen("alloc_log.txt", "wt");
freelog = fopen("free_log.txt", "wt");
finallog = fopen("final_log.txt", "wt");
#endif
}
/* add to counter and hash table if memory is allocated */
int memsaved(void *ptr) {
if (gc_is_on) {
gc_is_on = 0;
if (nghash_insert(memory_table, ptr, NULL) == NULL) {
#ifdef DB
mem_in++;
#ifdef DB_FULL
fprintf(alloclog, "0x%p\n", ptr);
#endif
#endif
} else
fprintf(stderr, "Warning: CPL GC Could not insert item into hashtable at 0x%p\n", ptr);
gc_is_on = 1;
}
return OK;
}
/* add to counter and remove from hash table if memory is deleted */
void memdeleted(const void *ptr) {
if (gc_is_on) {
gc_is_on = 0;
if (nghash_delete_special(memory_table, (void*)ptr) == NULL) {
#ifdef DB
mem_out++;
#ifdef DB_FULL
fprintf(freelog, "0x%p\n", ptr);
#endif
}
else if (ft_ngdebug)
fprintf(stderr, "Warning: CPL GC Could not delete item from hashtable at 0x%p\n", ptr);
#else
}
#endif
gc_is_on = 1;
}
}
/* helper functions */
void my_free_func(void *data)
{
if (data)
free(data);
}
void my_key_free(void * key)
{
if (key) {
free(key);
key = NULL;
#ifdef DB
mem_freed++;
#endif
}
}
/* free hash table, all entries and then the table itself */
void mem_delete(void) {
#ifdef DB
char buf[128];
if (!memory_table)
return;
printf("CPL GC memory allocated %d times, freed %d times\n", mem_in, mem_out);
printf("CPL GC size of hash table to be freed: %d entries.\n", nghash_get_size(memory_table));
#ifdef DB_FULL
void *data, *key;
data = nghash_enumeratek(memory_table, &key, TRUE);
for (void *hkey = key; hkey;) {
fprintf(finallog, "0x%p\n", hkey);
data = nghash_enumeratek(memory_table, &hkey, FALSE);
}
fclose(alloclog);
fclose(freelog);
fclose(finallog);
#endif
#endif
gc_is_on = 0;
nghash_free(memory_table, NULL, my_key_free);
memory_table = NULL;
#ifdef DB
/* printf via sh_printf will need some info from variables that have
been deleted already, therefore we use fputs */
sprintf(buf, "CPL GC number of addresses freed: %d entries.\n", mem_freed);
fputs(buf, stdout);
#endif
pool_vi = NULL;
mem_freed = mem_in = mem_out = 0;
}