e319b2f9d0780550d16b2dc8744932199af61fef
[stwbeast.git] / sfi / sfimemory.c
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   
46   if (mem_size >= TS8_SIZE && mem_size / 8 < SIMPLE_CACHE_SIZE)
47     {
48       guint cell;
49       
50       mem_size = (mem_size + 7) & ~0x7;
51       cell = (mem_size >> 3) - 1;
52       sfi_mutex_lock (&global_memory_mutex);
53       mem = g_trash_stack_pop (simple_cache + cell);
54       sfi_mutex_unlock (&global_memory_mutex);
55       if (!mem)
56         {
57           guint8 *cache_mem = g_malloc (mem_size * PREALLOC);
58           guint i;
59           
60           sfi_mutex_lock (&global_memory_mutex);
61           memory_allocated += mem_size * PREALLOC;
62           for (i = 0; i < PREALLOC - 1; i++)
63             {
64               g_trash_stack_push (simple_cache + cell, cache_mem);
65               cache_mem += mem_size;
66             }
67           sfi_mutex_unlock (&global_memory_mutex);
68           mem = cache_mem;
69         }
70     }
71   else
72     {
73       mem = g_malloc (mem_size);
74       sfi_mutex_lock (&global_memory_mutex);
75       memory_allocated += mem_size;
76       sfi_mutex_unlock (&global_memory_mutex);
77     }
78   return mem;
79 }
80
81 static inline void
82 low_free (gsize    mem_size,
83           gpointer mem)
84 {
85   if (mem_size >= TS8_SIZE && mem_size / 8 < SIMPLE_CACHE_SIZE)
86     {
87       guint cell;
88       
89       mem_size = (mem_size + 7) & ~0x7;
90       cell = (mem_size >> 3) - 1;
91       sfi_mutex_lock (&global_memory_mutex);
92       g_trash_stack_push (simple_cache + cell, mem);
93       sfi_mutex_unlock (&global_memory_mutex);
94     }
95   else
96     {
97       g_free (mem);
98       sfi_mutex_lock (&global_memory_mutex);
99       memory_allocated -= mem_size;
100       sfi_mutex_unlock (&global_memory_mutex);
101     }
102 }
103 #else
104 static inline gpointer
105 low_alloc (gsize mem_size)
106 {
107   return g_malloc (mem_size);
108 }
109 static inline void
110 low_free (gsize    mem_size,
111           gpointer mem)
112 {
113   g_free (mem);
114 }
115 #endif
116
117 gpointer
118 sfi_alloc_memblock (gsize block_size)
119 {
120   guint8 *cmem;
121   gsize *debug_size;
122   
123   g_return_val_if_fail (block_size >= sizeof (gpointer), NULL); /* cache-link size */
124   
125   cmem = low_alloc (block_size + DBG8_SIZE);
126   debug_size = (gsize*) cmem;
127   *debug_size = block_size;
128   cmem += DBG8_SIZE;
129   
130   return cmem;
131 }
132
133 void
134 sfi_free_memblock (gsize    block_size,
135                    gpointer mem)
136 {
137   gsize *debug_size;
138   guint8 *cmem;
139   
140   g_return_if_fail (mem != NULL);
141   
142   cmem = mem;
143   cmem -= DBG8_SIZE;
144   debug_size = (gsize*) cmem;
145   if (block_size != *debug_size)
146     g_printerr ("%s: in memory block at (%p): block_size=%zd != *debug_size=%zd\n", G_STRLOC, mem, block_size, *debug_size);
147   
148   low_free (block_size + DBG8_SIZE, cmem);
149 }
150
151 void
152 sfi_alloc_report (void)
153 {
154   guint cell, cached = 0;
155   
156   sfi_mutex_lock (&global_memory_mutex);
157   for (cell = 0; cell < SIMPLE_CACHE_SIZE; cell++)
158     {
159       GTrashStack *trash = simple_cache[cell];
160       guint memsize, n = 0;
161       
162       while (trash)
163         {
164           n++;
165           trash = trash->next;
166         }
167       
168       if (n)
169         {
170           memsize = (cell + 1) << 3;
171           g_message ("cell %4u): %u bytes in %u nodes", memsize, memsize * n, n);
172           cached += memsize * n;
173         }
174     }
175   g_message ("%lu bytes allocated from system, %u bytes unused in cache", memory_allocated, cached);
176   sfi_mutex_unlock (&global_memory_mutex);
177 }
178
179 gpointer
180 sfi_alloc_memblock0 (gsize block_size)
181 {
182   gpointer mem = sfi_alloc_memblock (block_size);
183   
184   memset (mem, 0, block_size);
185   
186   return mem;
187 }
188
189 void
190 _sfi_free_node_list (gpointer mem,
191                      gsize    node_size)
192 {
193   struct { gpointer data, next; } *tmp, *node = mem;
194   
195   g_return_if_fail (node != NULL);
196   g_return_if_fail (node_size >= 2 * sizeof (gpointer));
197   
198   /* FIXME: this can be optimized to an O(1) operation with T-style links in mem-caches */
199   do
200     {
201       tmp = node->next;
202       sfi_free_memblock (node_size, node);
203       node = tmp;
204     }
205   while (node);
206 }
207
208 void
209 _sfi_init_memory (void)
210 {
211   gboolean initialized = FALSE;
212   g_assert (initialized == FALSE);
213   initialized = TRUE;
214   sfi_mutex_init (&global_memory_mutex);
215 }