svn merge ^/trunk/blender -r43685:43693
[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 imperfect fix for performance issues caused
34         by vgroups.  it needs to be replaced with something better, preferably
35         integrated into guardedalloc.
36         
37         Basically, it's a quick fix for vgroups and MDisps (both of which
38         are major performance hitters).
39 */
40
41 #include "MEM_guardedalloc.h"
42
43 #include "BLI_utildefines.h"
44
45 #include "BLI_blenlib.h"
46 #include "BLI_linklist.h"
47
48 #include "DNA_listBase.h"
49 #include "BLI_mempool.h"
50
51 #include "BLI_cellalloc.h" /* own include */
52
53 #include <string.h> 
54
55 static BLI_mempool **pools;
56 static int totpool = 0;
57 static ListBase active_mem = {NULL, NULL};
58 static int celltotblock = 0;
59
60 #define MEMIDCHECK      ('a' | ('b' << 4) | ('c' << 8) | ('d' << 12))
61
62 typedef struct MemHeader {
63         struct MemHeader *next, *prev;
64
65         int size;
66         const char *tag;
67         int idcheck;
68 } MemHeader;
69
70 //#define USE_GUARDEDALLOC
71
72 void *BLI_cellalloc_malloc(int size, const char *tag)
73 {
74         MemHeader *memh;
75         int slot = size + sizeof(MemHeader);
76         
77 #ifdef USE_GUARDEDALLOC
78         return MEM_mallocN(size, tag);
79 #endif
80         if (!slot) 
81                 return NULL;
82         
83         /*stupid optimization trick.
84           round up to nearest 16 bytes boundary.
85           this is to reduce the number of potential
86           pools.  hopefully it'll help.*/
87         slot += 16 - (slot & 15);
88
89         if (slot >= totpool) {
90                 void *tmp;
91
92                 tmp = calloc(1, sizeof(void*)*(slot+1));
93                 if (pools) {
94                         memcpy(tmp, pools, totpool*sizeof(void*));
95                 }
96
97                 pools = tmp;
98                 totpool = slot+1;
99         }
100
101         if (!pools[slot]) {
102                 pools[slot] = BLI_mempool_create(slot, 1, 128, TRUE, FALSE);
103         }
104
105         memh = BLI_mempool_alloc(pools[slot]);
106         memh->size = size;
107         memh->idcheck = MEMIDCHECK;
108         memh->tag = tag;
109         BLI_addtail(&active_mem, memh);
110         celltotblock++;
111
112         return memh + 1;
113 }
114
115 void *BLI_cellalloc_calloc(int size, const char *tag)
116 {
117         void *mem = BLI_cellalloc_malloc(size, tag);
118         memset(mem, 0, size);
119         return mem;
120 }
121
122 void BLI_cellalloc_free(void *mem)
123 {
124         MemHeader *memh = mem;
125         int slot;
126
127 #ifdef USE_GUARDEDALLOC
128         MEM_freeN(mem);
129         return;
130 #endif
131         if (!memh)
132                 return;
133
134         memh--;
135         if (memh->idcheck != MEMIDCHECK) {
136                 printf("Error in BLI_cellalloc: attempt to free invalid block.\n");
137                 return;
138         }
139         
140         slot = memh->size + sizeof(MemHeader);
141         slot += 16 - (slot & 15);
142
143         if (memh->size > 0 && slot < totpool) {
144                 BLI_remlink(&active_mem, memh);
145                 BLI_mempool_free(pools[slot], memh);
146                 celltotblock--;
147         } else {
148                 printf("Error in BLI_cellalloc: attempt to free corrupted block.\n");
149         }
150 }
151
152 void *BLI_cellalloc_dupalloc(void *mem)
153 {
154         MemHeader *memh = mem;
155         void *tmp;
156
157 #ifdef USE_GUARDEDALLOC
158         MEM_freeN(mem);
159         return NULL;
160 #endif
161         if (!memh)
162                 return NULL;
163
164         memh--;
165         if (memh->idcheck != MEMIDCHECK) {
166                 printf("Error in BLI_cellalloc: attempt to free invalid block.\n");
167                 return NULL;
168         }
169
170         tmp = BLI_cellalloc_malloc(memh->size, memh->tag);
171         memcpy(tmp, mem, memh->size);
172
173         return tmp;
174 }
175
176 void BLI_cellalloc_printleaks(void)
177 {
178         MemHeader *memh;
179
180         if (!active_mem.first) return;
181
182         for (memh=active_mem.first; memh; memh=memh->next) {
183                 printf("%s %d %p\n", memh->tag, memh->size, memh+1);
184         }
185 }
186
187 int BLI_cellalloc_get_totblock(void)
188 {
189         return celltotblock;
190 }
191
192 void BLI_cellalloc_destroy(void)
193 {
194         int i;
195
196         for (i=0; i<totpool; i++) {
197                 if (pools[i]) {
198                         BLI_mempool_destroy(pools[i]);
199                         pools[i] = NULL;
200                 }
201         }
202 }