SFI: compile sfimemory.c as C++ source
[stwbeast.git] / sfi / sfimemory.cc
1 /* SFI - Synthesis Fusion Kit Interface
2  * Copyright (C) 2002 Tim Janik and Stefan Westerfeld
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * A copy of the GNU Lesser General Public License should ship along
15  * with this library; if not, see http://www.gnu.org/copyleft/.
16  */
17 #include "sfimemory.h"
18 #include <string.h>
19
20
21 #define PREALLOC                (8)
22 #define SIMPLE_CACHE_SIZE       (64)
23 #define TS8_SIZE                (MAX (sizeof (GTrashStack), 8))
24 #define DBG8_SIZE               (MAX (sizeof (gsize), 8))
25
26
27 /* --- variables --- */
28 static BirnetMutex     global_memory_mutex = { 0, };
29 static GTrashStack *simple_cache[SIMPLE_CACHE_SIZE] = { 0, 0, 0, /* ... */ };
30 static gulong       memory_allocated = 0;
31
32
33 /* --- functions --- */
34 gulong
35 sfi_alloc_upper_power2 (const gulong number)
36 {
37   return number ? 1 << g_bit_storage (number - 1) : 0;
38 }
39
40 #if 0
41 static inline gpointer
42 low_alloc (gsize mem_size)
43 {
44   gpointer mem;
45   if (mem_size >= TS8_SIZE && mem_size / 8 < SIMPLE_CACHE_SIZE)
46     {
47       guint cell;
48       mem_size = (mem_size + 7) & ~0x7;
49       cell = (mem_size >> 3) - 1;
50       sfi_mutex_lock (&global_memory_mutex);
51       mem = g_trash_stack_pop (simple_cache + cell);
52       sfi_mutex_unlock (&global_memory_mutex);
53       if (!mem)
54         {
55           guint8 *cache_mem = g_malloc (mem_size * PREALLOC);
56           guint i;
57           sfi_mutex_lock (&global_memory_mutex);
58           memory_allocated += mem_size * PREALLOC;
59           for (i = 0; i < PREALLOC - 1; i++)
60             {
61               g_trash_stack_push (simple_cache + cell, cache_mem);
62               cache_mem += mem_size;
63             }
64           sfi_mutex_unlock (&global_memory_mutex);
65           mem = cache_mem;
66         }
67     }
68   else
69     {
70       mem = g_malloc (mem_size);
71       sfi_mutex_lock (&global_memory_mutex);
72       memory_allocated += mem_size;
73       sfi_mutex_unlock (&global_memory_mutex);
74     }
75   return mem;
76 }
77
78 static inline void
79 low_free (gsize    mem_size,
80           gpointer mem)
81 {
82   if (mem_size >= TS8_SIZE && mem_size / 8 < SIMPLE_CACHE_SIZE)
83     {
84       uint cell;
85       mem_size = (mem_size + 7) & ~0x7;
86       cell = (mem_size >> 3) - 1;
87       sfi_mutex_lock (&global_memory_mutex);
88       g_trash_stack_push (simple_cache + cell, mem);
89       sfi_mutex_unlock (&global_memory_mutex);
90     }
91   else
92     {
93       g_free (mem);
94       sfi_mutex_lock (&global_memory_mutex);
95       memory_allocated -= mem_size;
96       sfi_mutex_unlock (&global_memory_mutex);
97     }
98 }
99 #else
100 static inline gpointer
101 low_alloc (gsize mem_size)
102 {
103   return g_malloc (mem_size);
104 }
105 static inline void
106 low_free (gsize    mem_size,
107           gpointer mem)
108 {
109   g_free (mem);
110 }
111 #endif
112
113 gpointer
114 sfi_alloc_memblock (gsize block_size)
115 {
116   uint8 *cmem;
117   size_t *debug_size;
118
119   g_return_val_if_fail (block_size >= sizeof (gpointer), NULL); /* cache-link size */
120
121   cmem = (uint8*) low_alloc (block_size + DBG8_SIZE);
122   debug_size = (gsize*) cmem;
123   *debug_size = block_size;
124   cmem += DBG8_SIZE;
125
126   return cmem;
127 }
128
129 void
130 sfi_free_memblock (gsize    block_size,
131                    gpointer mem)
132 {
133   size_t *debug_size;
134   uint8 *cmem;
135   
136   g_return_if_fail (mem != NULL);
137   
138   cmem = (uint8*) mem;
139   cmem -= DBG8_SIZE;
140   debug_size = (gsize*) cmem;
141   if (block_size != *debug_size)
142     g_printerr ("%s: in memory block at (%p): block_size=%zd != *debug_size=%zd\n", G_STRLOC, mem, block_size, *debug_size);
143   
144   low_free (block_size + DBG8_SIZE, cmem);
145 }
146
147 void
148 sfi_alloc_report (void)
149 {
150   guint cell, cached = 0;
151   
152   sfi_mutex_lock (&global_memory_mutex);
153   for (cell = 0; cell < SIMPLE_CACHE_SIZE; cell++)
154     {
155       GTrashStack *trash = simple_cache[cell];
156       guint memsize, n = 0;
157       
158       while (trash)
159         {
160           n++;
161           trash = trash->next;
162         }
163       
164       if (n)
165         {
166           memsize = (cell + 1) << 3;
167           g_message ("cell %4u): %u bytes in %u nodes", memsize, memsize * n, n);
168           cached += memsize * n;
169         }
170     }
171   g_message ("%lu bytes allocated from system, %u bytes unused in cache", memory_allocated, cached);
172   sfi_mutex_unlock (&global_memory_mutex);
173 }
174
175 gpointer
176 sfi_alloc_memblock0 (gsize block_size)
177 {
178   gpointer mem = sfi_alloc_memblock (block_size);
179   
180   memset (mem, 0, block_size);
181   
182   return mem;
183 }
184
185 void
186 _sfi_free_node_list (gpointer mem,
187                      gsize    node_size)
188 {
189   struct LinkedData { gpointer data; LinkedData *next; };
190   LinkedData *tmp, *node = (LinkedData*) mem;
191
192   g_return_if_fail (node != NULL);
193   g_return_if_fail (node_size >= 2 * sizeof (gpointer));
194
195   /* FIXME: this can be optimized to an O(1) operation with T-style links in mem-caches */
196   do
197     {
198       tmp = node->next;
199       sfi_free_memblock (node_size, node);
200       node = tmp;
201     }
202   while (node);
203 }
204
205 void
206 _sfi_init_memory (void)
207 {
208   gboolean initialized = FALSE;
209   g_assert (initialized == FALSE);
210   initialized = TRUE;
211   sfi_mutex_init (&global_memory_mutex);
212 }