diff options
Diffstat (limited to '')
-rw-r--r-- | linden/indra/llcommon/llpagemem.h | 392 |
1 files changed, 392 insertions, 0 deletions
diff --git a/linden/indra/llcommon/llpagemem.h b/linden/indra/llcommon/llpagemem.h new file mode 100644 index 0000000..7081251 --- /dev/null +++ b/linden/indra/llcommon/llpagemem.h | |||
@@ -0,0 +1,392 @@ | |||
1 | /** | ||
2 | * @file llpagemem.h | ||
3 | * | ||
4 | * Copyright (c) 2002-2007, Linden Research, Inc. | ||
5 | * | ||
6 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
7 | * to you under the terms of the GNU General Public License, version 2.0 | ||
8 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
9 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
10 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
11 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
12 | * | ||
13 | * There are special exceptions to the terms and conditions of the GPL as | ||
14 | * it is applied to this Source Code. View the full text of the exception | ||
15 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
16 | * online at http://secondlife.com/developers/opensource/flossexception | ||
17 | * | ||
18 | * By copying, modifying or distributing this software, you acknowledge | ||
19 | * that you have read and understood your obligations described above, | ||
20 | * and agree to abide by those obligations. | ||
21 | * | ||
22 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
23 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
24 | * COMPLETENESS OR PERFORMANCE. | ||
25 | */ | ||
26 | #ifndef LL_LLPAGEMEM_H | ||
27 | #define LL_LLPAGEMEM_H | ||
28 | |||
29 | #if !LL_DARWIN | ||
30 | #include "malloc.h" | ||
31 | #endif | ||
32 | |||
33 | #include "llrand.h" | ||
34 | |||
35 | |||
36 | #ifndef __GNUC__ | ||
37 | template <class Object, U32 mPageSize=1024> | ||
38 | class LLPageMemory | ||
39 | { | ||
40 | private: | ||
41 | |||
42 | union XObject | ||
43 | { | ||
44 | XObject *mNextFreeObject; | ||
45 | U8 mObject[sizeof(Object)]; | ||
46 | }; | ||
47 | |||
48 | template <U32 mPageSize> struct Page | ||
49 | { | ||
50 | XObject *mFirstFreeObject; | ||
51 | U32 mObjectCount; | ||
52 | U8 mObjects[mPageSize-8]; | ||
53 | |||
54 | void init(U32 mObjPerPage) | ||
55 | { | ||
56 | XObject *o = (XObject*)&mObjects; | ||
57 | mObjectCount = 0; | ||
58 | mFirstFreeObject = o; | ||
59 | |||
60 | for (U32 i = 0; i < mObjPerPage-1; i++) | ||
61 | { | ||
62 | o->mNextFreeObject = o+1; | ||
63 | o++; | ||
64 | } | ||
65 | o->mNextFreeObject = NULL; | ||
66 | }; | ||
67 | |||
68 | Object* alloc() | ||
69 | { | ||
70 | if (mFirstFreeObject) | ||
71 | { | ||
72 | XObject *ret = mFirstFreeObject; | ||
73 | mFirstFreeObject = mFirstFreeObject->mNextFreeObject; | ||
74 | ret->mNextFreeObject = NULL; | ||
75 | mObjectCount++; | ||
76 | return (Object*)&ret->mObject; | ||
77 | }; | ||
78 | return NULL; | ||
79 | } | ||
80 | }; | ||
81 | |||
82 | U32 mObjPerPage; | ||
83 | U32 mMaxPages; | ||
84 | U32 mObjectCount; | ||
85 | |||
86 | Page<mPageSize>* mPageMemory; | ||
87 | Page<mPageSize>* mFirstPage; | ||
88 | |||
89 | public: | ||
90 | U32 precise, anywhere, fail; | ||
91 | |||
92 | void init() | ||
93 | { | ||
94 | Page<mPageSize> *p = mFirstPage; | ||
95 | for (U32 i = 0; i < mMaxPages; i++) | ||
96 | { | ||
97 | p[i].init(mObjPerPage); | ||
98 | } | ||
99 | |||
100 | precise = 0; | ||
101 | anywhere = 0; | ||
102 | fail = 0; | ||
103 | }; | ||
104 | |||
105 | public: | ||
106 | |||
107 | Page<mPageSize>* pageof(Object *object) | ||
108 | { | ||
109 | return (Page<mPageSize>*) ((((U32)object - 8) / mPageSize) * mPageSize ); | ||
110 | } | ||
111 | |||
112 | LLPageMemory(U32 maxObjects) | ||
113 | { | ||
114 | mObjPerPage = (mPageSize-8) / sizeof(Object); | ||
115 | mMaxPages = (maxObjects / mObjPerPage) + 1; | ||
116 | mObjectCount= 0; | ||
117 | |||
118 | //printf("%d objects per page, %d pages total, %d/%d objects\n", | ||
119 | // mObjPerPage, mMaxPages, mMaxPages * mObjPerPage,maxObjects); | ||
120 | |||
121 | mPageMemory = (Page<mPageSize>*)calloc(mPageSize,mMaxPages+1); | ||
122 | mFirstPage = mPageMemory; | ||
123 | U32 fix = ((U32)mPageMemory % mPageSize); | ||
124 | if (fix) mFirstPage = (Page<mPageSize>*)((U32)mPageMemory+mPageSize-fix); | ||
125 | |||
126 | //printf("fix = %d\n",fix); | ||
127 | |||
128 | init(); | ||
129 | }; | ||
130 | |||
131 | LLPageMemory(void *pageMem, U32 bytes) | ||
132 | { | ||
133 | } | ||
134 | |||
135 | ~LLPageMemory() | ||
136 | { | ||
137 | if (mPageMemory) | ||
138 | { | ||
139 | free(mPageMemory); | ||
140 | } | ||
141 | } | ||
142 | |||
143 | Object* alloc(Object *after=NULL) | ||
144 | { | ||
145 | Page<mPageSize> * p = mFirstPage; | ||
146 | Object * o = NULL; | ||
147 | U32 i = mMaxPages; | ||
148 | |||
149 | if (after) | ||
150 | { | ||
151 | o = pageof(after)->alloc(); | ||
152 | if (o) | ||
153 | { | ||
154 | precise++; | ||
155 | return o; | ||
156 | } | ||
157 | return NULL; | ||
158 | } | ||
159 | |||
160 | F32 frac = 1.0f / (F32)mMaxPages; | ||
161 | F32 thresh = 0.0f; | ||
162 | for (i = 0; i < mMaxPages; i++) | ||
163 | { | ||
164 | if (thresh > ((F32)p[i].mObjectCount / (F32)mObjPerPage)) | ||
165 | { | ||
166 | o = p[i].alloc(); | ||
167 | if (o) | ||
168 | { | ||
169 | //printf("allocating page %x obj %x\n",p, o); | ||
170 | anywhere++; | ||
171 | return o; | ||
172 | } | ||
173 | } | ||
174 | thresh += frac; | ||
175 | } | ||
176 | |||
177 | fail++; | ||
178 | return NULL; | ||
179 | }; | ||
180 | |||
181 | void free(Object *o) | ||
182 | { | ||
183 | if (!o) return; | ||
184 | |||
185 | Page<mPageSize> *page = pageof(o); | ||
186 | XObject *obj = (XObject*)o; | ||
187 | |||
188 | //printf("freeing %x\n",obj); | ||
189 | |||
190 | obj->mNextFreeObject = page->mFirstFreeObject; | ||
191 | page->mFirstFreeObject = obj; | ||
192 | page->mObjectCount--; | ||
193 | |||
194 | //printf("freeing page %x %d\n",page, page->mObjectCount); | ||
195 | }; | ||
196 | |||
197 | U32 indexof(Object *object) | ||
198 | { | ||
199 | if (!object) return -1; | ||
200 | |||
201 | return ((((U32)object-8) % mPageSize) / sizeof(Object)) + | ||
202 | ((pageof(object) - mFirstPage) * mObjPerPage); | ||
203 | } | ||
204 | |||
205 | |||
206 | void dump() | ||
207 | { | ||
208 | |||
209 | for (U32 i=0;i < mMaxPages;i++) | ||
210 | { | ||
211 | //printf("page %d %d/%d objects\n",i,mFirstPage[i].mObjectCount,mObjPerPage); | ||
212 | } | ||
213 | //printf("precise = %d anywhere %d ratio = %f\n",precise,anywhere,(F32)precise/(F32)(anywhere+precise)); | ||
214 | //printf("fail = %d\n",fail); | ||
215 | |||
216 | } | ||
217 | |||
218 | static void test() | ||
219 | { | ||
220 | struct Foo | ||
221 | { | ||
222 | U32 ord; | ||
223 | U32 foo[8]; | ||
224 | }; | ||
225 | |||
226 | const U32 count = 100; | ||
227 | U32 i,c; | ||
228 | U32 mix = 50; | ||
229 | |||
230 | LLPageMemory<Foo> mem(count); | ||
231 | LLRand rand(LLUUID::getRandomSeed()); | ||
232 | |||
233 | Foo *obj[count]; | ||
234 | |||
235 | for (i=0;i<count;i++) obj[i] = 0; | ||
236 | |||
237 | U32 x= 0; | ||
238 | for (U32 run=0; run < 10000 ;run++) | ||
239 | { | ||
240 | U32 m =rand.llrand(count); | ||
241 | for (c=0;c < m;c++) | ||
242 | { | ||
243 | U32 j = rand.llrand(count); | ||
244 | if (obj[j]) | ||
245 | { | ||
246 | mem.free(obj[j]); | ||
247 | obj[j] = 0; | ||
248 | } | ||
249 | } | ||
250 | |||
251 | m =rand.llrand(count); | ||
252 | for (c=0;c<m;c++) | ||
253 | { | ||
254 | U32 i = rand.llrand(count); | ||
255 | while (obj[i] && i < count) i++; | ||
256 | |||
257 | if (!obj[i]) | ||
258 | { | ||
259 | if (i > 0) obj[i] = mem.alloc(obj[i-1]); | ||
260 | else obj[i] = mem.alloc(); | ||
261 | if (obj[i]) obj[i]->ord = x++; | ||
262 | } | ||
263 | } | ||
264 | } | ||
265 | |||
266 | for (i = 0; i< count; i++) | ||
267 | { | ||
268 | //printf("obj[%2d] = %08x %02d %4d\n",i,obj[i],mem.indexof(obj[i]),(obj[i] ? obj[i]->ord : -1)); | ||
269 | } | ||
270 | |||
271 | mem.dump(); | ||
272 | } | ||
273 | }; | ||
274 | |||
275 | |||
276 | template <class Object> | ||
277 | class LLObjectPool | ||
278 | { | ||
279 | private: | ||
280 | |||
281 | class XObject | ||
282 | { | ||
283 | public: | ||
284 | Object mObject; | ||
285 | U32 mNextFreeObject; | ||
286 | |||
287 | XObject() { mObject = NULL; mNextFreeObject = 0; } | ||
288 | }; | ||
289 | |||
290 | U32 mNumObjects; | ||
291 | U32 mMaxObjects; | ||
292 | XObject* mObjects; | ||
293 | U32 mFirstFreeObject; | ||
294 | |||
295 | U32 indexof(XObject *xobj) { return (xobj - mObjects); } | ||
296 | |||
297 | public: | ||
298 | LLObjectPool(U32 maxObjects) | ||
299 | { | ||
300 | mMaxObjects = maxObjects; | ||
301 | mFirstFreeObject = 0; | ||
302 | |||
303 | mObjects = new XObject[mMaxObjects]; | ||
304 | |||
305 | //printf("objectpool allocated %d bytes\n",sizeof(XObject) * mMaxObjects); | ||
306 | |||
307 | for (U32 i=0;i<mMaxObjects;i++) mObjects[i].mNextFreeObject = i+1; | ||
308 | }; | ||
309 | |||
310 | ~LLObjectPool() | ||
311 | { | ||
312 | delete [] mObjects; | ||
313 | mObjects = NULL; | ||
314 | } | ||
315 | |||
316 | Object* alloc(Object *after=NULL) | ||
317 | { | ||
318 | XObject *obj = &mObjects[mFirstFreeObject]; | ||
319 | mFirstFreeObject = obj->mNextFreeObject; | ||
320 | if (mFirstFreeObject >= mMaxObjects) | ||
321 | { | ||
322 | llerrs << "Attempted to allocate too many objects out of pool\n" << llendl; | ||
323 | llassert(0); | ||
324 | } | ||
325 | return &obj->mObject; | ||
326 | }; | ||
327 | |||
328 | void free(Object *obj) | ||
329 | { | ||
330 | if (!obj) return; | ||
331 | XObject *xobj = (XObject*)obj; | ||
332 | xobj->mNextFreeObject = mFirstFreeObject; | ||
333 | mFirstFreeObject = indexof(xobj); | ||
334 | }; | ||
335 | |||
336 | static void test() | ||
337 | { | ||
338 | struct Foo | ||
339 | { | ||
340 | U32 ord; | ||
341 | U32 foo[8]; | ||
342 | }; | ||
343 | |||
344 | const U32 count = 100; | ||
345 | U32 i,c; | ||
346 | U32 mix = 50; | ||
347 | |||
348 | LLPageMemory<Foo> mem(count); | ||
349 | LLRand rand(LLUUID::getRandomSeed()); | ||
350 | |||
351 | Foo *obj[count]; | ||
352 | |||
353 | for (i=0;i<count;i++) obj[i] = 0; | ||
354 | |||
355 | U32 x= 0; | ||
356 | for (U32 run=0; run < 10000 ;run++) | ||
357 | { | ||
358 | U32 m =rand.llrand(count); | ||
359 | for (c=0;c < m;c++) | ||
360 | { | ||
361 | U32 j = rand.llrand(count); | ||
362 | if (obj[j]) | ||
363 | { | ||
364 | mem.free(obj[j]); | ||
365 | obj[j] = 0; | ||
366 | } | ||
367 | } | ||
368 | |||
369 | m =rand.llrand(count); | ||
370 | for (c=0;c<m;c++) | ||
371 | { | ||
372 | U32 i = rand.llrand(count); | ||
373 | while (obj[i] && i < count) i++; | ||
374 | |||
375 | if (!obj[i]) | ||
376 | { | ||
377 | if (i > 0) obj[i] = mem.alloc(obj[i-1]); | ||
378 | else obj[i] = mem.alloc(); | ||
379 | if (obj[i]) obj[i]->ord = x++; | ||
380 | } | ||
381 | } | ||
382 | } | ||
383 | |||
384 | for (i = 0; i< count; i++) | ||
385 | { | ||
386 | //printf("obj[%2d] = %08x %02d %4d\n",i,obj[i],mem.indexof(obj[i]),(obj[i] ? obj[i]->ord : -1)); | ||
387 | } | ||
388 | } | ||
389 | }; | ||
390 | #endif // !defined __GNUC__ | ||
391 | |||
392 | #endif | ||