- free(info);
-}
-
-void *util_memory_r(void *ptrn, size_t byte, unsigned int line, const char *file) {
- struct memblock_t *oldinfo = NULL;
-
- struct memblock_t *newinfo;
-
- if (!ptrn)
- return util_memory_a(byte, line, file);
- if (!byte) {
- util_memory_d(ptrn);
- return NULL;
- }
-
- oldinfo = ((struct memblock_t*)ptrn - 1);
- newinfo = ((struct memblock_t*)malloc(sizeof(struct memblock_t) + byte));
-
- /* new data */
- if (!newinfo) {
- util_memory_d(oldinfo+1);
- return NULL;
- }
-
- /* copy old */
- memcpy(newinfo+1, oldinfo+1, oldinfo->byte);
-
- /* free old */
- if (oldinfo->prev)
- oldinfo->prev->next = oldinfo->next;
- if (oldinfo->next)
- oldinfo->next->prev = oldinfo->prev;
- if (oldinfo == mem_start)
- mem_start = oldinfo->next;
-
- /* fill info */
- newinfo->line = line;
- newinfo->byte = byte;
- newinfo->file = file;
- newinfo->prev = NULL;
- newinfo->next = mem_start;
- if (mem_start)
- mem_start->prev = newinfo;
- mem_start = newinfo;
-
- mem_ab -= oldinfo->byte;
- mem_hw -= oldinfo->byte;
- mem_ab += newinfo->byte;
- mem_hw += newinfo->byte;
-
- PEAK_MEM;
-
- free(oldinfo);
-
- return newinfo+1;
-}
-
-static void util_dumpmem(struct memblock_t *memory, uint16_t cols) {
- uint32_t i, j;
- for (i = 0; i < memory->byte + ((memory->byte % cols) ? (cols - memory->byte % cols) : 0); i++) {
- if (i % cols == 0) con_out(" 0x%06X: ", i);
- if (i < memory->byte) con_out("%02X " , 0xFF & ((char*)(memory + 1))[i]);
- else con_out(" ");
-
- if ((uint16_t)(i % cols) == (cols - 1)) {
- for (j = i - (cols - 1); j <= i; j++) {
- con_out("%c",
- (j >= memory->byte)
- ? ' '
- : (isprint(((char*)(memory + 1))[j]))
- ? 0xFF & ((char*)(memory + 1)) [j]
- : '.'
- );
- }
- con_out("\n");
- }
- }
-}
-
-/*
- * The following is a VERY tight, efficent, hashtable for integer
- * values and keys, and for nothing more. We could make our existing
- * hashtable support type-genericness through a void * pointer but,
- * ideally that would make things more complicated. We also don't need
- * that much of a bloat for something as basic as this.
- */
-typedef struct {
- size_t key;
- size_t value;
-} size_entry_t;
-#define ST_SIZE 1024
-
-typedef size_entry_t **size_table_t;
-
-size_table_t util_st_new() {
- return (size_table_t)memset(
- mem_a(sizeof(size_entry_t*) * ST_SIZE),
- 0, ST_SIZE * sizeof(size_entry_t*)
- );
-}
-void util_st_del(size_table_t table) {
- size_t i = 0;
- for (; i < ST_SIZE; i++) if(table[i]) mem_d(table[i]);
- mem_d(table);
-}
-size_entry_t *util_st_get(size_table_t table, size_t key) {
- size_t hash = (key % ST_SIZE);
- while (table[hash] && table[hash]->key != key)
- hash = (hash + 1) % ST_SIZE;
- return table[hash];
-}
-void util_st_put(size_table_t table, size_t key, size_t value) {
- size_t hash = (key % ST_SIZE);
- while (table[hash] && table[hash]->key != key)
- hash = (hash + 1) % ST_SIZE;
- table[hash] = (size_entry_t*)mem_a(sizeof(size_entry_t));
- table[hash]->key = key;
- table[hash]->value = value;
-}
-
-static uint64_t strdups = 0;
-static uint64_t vectors = 0;
-static uint64_t vector_sizes = 0;
-static uint64_t hashtables = 0;
-static uint64_t hashtable_sizes = 0;
-static size_table_t vector_usage = NULL;
-static size_table_t hashtable_usage = NULL;
-
-void util_meminfo() {
- struct memblock_t *info;
-
- if (OPTS_OPTION_BOOL(OPTION_DEBUG)) {
- for (info = mem_start; info; info = info->next) {
- con_out("lost: %u (bytes) at %s:%u\n",
- info->byte,
- info->file,
- info->line);
-
- util_dumpmem(info, OPTS_OPTION_U16(OPTION_MEMDUMPCOLS));
- }
- }
-
- if (OPTS_OPTION_BOOL(OPTION_DEBUG) ||
- OPTS_OPTION_BOOL(OPTION_MEMCHK)) {
- con_out("Memory information:\n\
- Total allocations: %llu\n\
- Total deallocations: %llu\n\
- Total allocated: %f (MB)\n\
- Total deallocated: %f (MB)\n\
- Total peak memory: %f (MB)\n\
- Total leaked memory: %f (MB) in %llu allocations\n",
- mem_at,
- mem_dt,
- (float)(mem_ab) / 1048576.0f,
- (float)(mem_db) / 1048576.0f,
- (float)(mem_pk) / 1048576.0f,
- (float)(mem_ab - mem_db) / 1048576.0f,
-
- /* could be more clever */
- (mem_at - mem_dt)
- );
- }
-
- if (OPTS_OPTION_BOOL(OPTION_STATISTICS) ||
- OPTS_OPTION_BOOL(OPTION_MEMCHK)) {
- size_t i = 0;
- size_t e = 1;
- uint64_t vectormem = 0;
-
- con_out("\nAdditional Statistics:\n\
- Total vectors allocated: %llu\n\
- Total string duplicates: %llu\n\
- Total hashtables allocated: %llu\n\
- Total unique vector sizes: %llu\n",
- vectors,
- strdups,
- hashtables,
- vector_sizes
- );
-
- for (; i < ST_SIZE; i++) {
- size_entry_t *entry;
-
- if (!(entry = vector_usage[i]))
- continue;
-
- con_out(" %2u| # of %4u byte vectors: %u\n",
- (unsigned)e,
- (unsigned)entry->key,
- (unsigned)entry->value
- );
- e++;
-
- vectormem += entry->key * entry->value;
- }
-
- con_out("\
- Total unique hashtable sizes: %llu\n",
- hashtable_sizes
- );
-
- for (i = 0, e = 1; i < ST_SIZE; i++) {
- size_entry_t *entry;
-
- if (!(entry = hashtable_usage[i]))
- continue;
-
- con_out(" %2u| # of %4u element hashtables: %u\n",
- (unsigned)e,
- (unsigned)entry->key,
- (unsigned)entry->value
- );
- e++;
- }
-
- con_out(" Total vector memory: %f (MB)\n",
- (float)(vectormem) / 1048576.0f
- );
- }
-
- if (vector_usage)
- util_st_del(vector_usage);
- if (hashtable_usage)
- util_st_del(hashtable_usage);
-}
-
-/*
- * Some string utility functions, because strdup uses malloc, and we want
- * to track all memory (without replacing malloc).
- */
-char *_util_Estrdup(const char *s, const char *file, size_t line) {
- size_t len = 0;
- char *ptr = NULL;
-
- /* in case of -DNOTRACK */
- (void)file;
- (void)line;
-
- if (!s)
- return NULL;
-
- if ((len = strlen(s)) && (ptr = (char*)mem_af(len+1, line, file))) {
- memcpy(ptr, s, len);
- ptr[len] = '\0';
- }
- strdups++;
- return ptr;
-}
-
-char *_util_Estrdup_empty(const char *s, const char *file, size_t line) {
- size_t len = 0;
- char *ptr = NULL;
-
- /* in case of -DNOTRACK */
- (void)file;
- (void)line;
-
- if (!s)
- return NULL;
-
- len = strlen(s);
- if ((ptr = (char*)mem_af(len+1, line, file))) {
- memcpy(ptr, s, len);
- ptr[len] = '\0';
- }
- strdups++;
- return ptr;
-}