merge with/from trunk at r35190
[blender.git] / source / blender / blenlib / intern / BLI_cellalloc.c
1 /**
2  *
3  * ***** BEGIN GPL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  *
19  * The Original Code is Copyright (C) 2008 by Blender Foundation.
20  * All rights reserved.
21  *
22  * The Original Code is: all of this file.
23  *
24  * Contributor(s): Joseph Eagar
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 /*
30         Simple, fast memory allocator that uses many BLI_mempools for allocation.
31         this is meant to be used by lots of relatively small objects.
32
33         this is a temporary and inperfect fix for performance issues caused
34         by vgroups.  it needs to be replaced with something better, preferably
35         integrated into guardedalloc.
36 */
37
38 #include "MEM_guardedalloc.h"
39
40 #include "BKE_utildefines.h"
41
42 #include "BLI_blenlib.h"
43 #include "BLI_linklist.h"
44
45 #include "DNA_listBase.h"
46 #include "BLI_mempool.h"
47
48 #include <string.h> 
49
50 static BLI_mempool **pools;
51 static int totpool = 0;
52 ListBase active_mem = {NULL, NULL};
53 static int celltotblock = 0;
54
55 #define MEMIDCHECK      ('a' | ('b' << 4) | ('c' << 8) | ('d' << 12))
56
57 typedef struct MemHeader {
58         struct MemHeader *next, *prev;
59
60         int size;
61         char *tag;
62         int idcheck;
63 } MemHeader;
64
65 //#define USE_GUARDEDALLOC
66
67 void *BLI_cellalloc_malloc(long size, char *tag)
68 {
69         MemHeader *memh;
70         int slot = size + sizeof(MemHeader);
71         
72 #ifdef USE_GUARDEDALLOC
73         return MEM_mallocN(size, tag);
74 #endif
75         if (!slot) 
76                 return NULL;
77         
78         /*stupid optimization trick.
79           round up to nearest 16 bytes boundary.
80           this is to reduce the number of potential
81           pools.  hopefully it'll help.*/
82         slot += 16 - (slot & 15);
83
84         if (slot >= totpool) {
85                 void *tmp;
86
87                 tmp = calloc(1, sizeof(void*)*(slot+1));
88                 if (pools) {
89                         memcpy(tmp, pools, totpool*sizeof(void*));
90                 }
91
92                 pools = tmp;
93                 totpool = slot+1;
94         }
95
96         if (!pools[slot]) {
97                 pools[slot] = BLI_mempool_create(slot, 1, 128, 1, 0);
98         }
99
100         memh = BLI_mempool_alloc(pools[slot]);
101         memh->size = size;
102         memh->idcheck = MEMIDCHECK;
103         memh->tag = tag;
104         BLI_addtail(&active_mem, memh);
105         celltotblock++;
106
107         return memh + 1;
108 }
109
110 void *BLI_cellalloc_calloc(long size, char *tag)
111 {
112         void *mem = BLI_cellalloc_malloc(size, tag);
113         BMEMSET(mem, 0, size);
114
115         return mem;
116 }
117
118 void BLI_cellalloc_free(void *mem)
119 {
120         MemHeader *memh = mem;
121         int slot;
122
123 #ifdef USE_GUARDEDALLOC
124         MEM_freeN(mem);
125         return;
126 #endif
127         if (!memh)
128                 return;
129
130         memh--;
131         if (memh->idcheck != MEMIDCHECK) {
132                 printf("Error in BLI_cellalloc: attempt to free invalid block.\n");
133                 return;
134         }
135         
136         slot = memh->size + sizeof(MemHeader);
137         slot += 16 - (slot & 15);
138
139         if (memh->size > 0 && slot < totpool) {
140                 BLI_remlink(&active_mem, memh);
141                 BLI_mempool_free(pools[slot], memh);
142                 celltotblock--;
143         } else {
144                 printf("Error in BLI_cellalloc: attempt to free corrupted block.\n");
145         }
146 }
147
148 void *BLI_cellalloc_dupalloc(void *mem)
149 {
150         MemHeader *memh = mem;
151         void *tmp;
152
153 #ifdef USE_GUARDEDALLOC
154         MEM_freeN(mem);
155         return NULL;
156 #endif
157         if (!memh)
158                 return NULL;
159
160         memh--;
161         if (memh->idcheck != MEMIDCHECK) {
162                 printf("Error in BLI_cellalloc: attempt to free invalid block.\n");
163                 return NULL;
164         }
165
166         tmp = BLI_cellalloc_malloc(memh->size, memh->tag);
167         memcpy(tmp, mem, memh->size);
168
169         return tmp;
170 }
171
172 void BLI_cellalloc_printleaks(void)
173 {
174         MemHeader *memh;
175
176         if (!active_mem.first) return;
177
178         for (memh=active_mem.first; memh; memh=memh->next) {
179                 printf("%s %d %p\n", memh->tag, memh->size, memh+1);
180         }
181 }
182
183 int BLI_cellalloc_get_totblock(void)
184 {
185         return celltotblock;
186 }
187
188 void BLI_cellalloc_destroy(void)
189 {
190         int i;
191
192         for (i=0; i<totpool; i++) {
193                 if (pools[i]) {
194                         BLI_mempool_destroy(pools[i]);
195                         pools[i] = NULL;
196                 }
197         }
198 }