2 * Copyright (c) 2000, 2001 Ximian Inc.
4 * Authors: Michael Zucchi <notzed@ximian.com>
5 * Jacob Berkman <jacob@ximian.com>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of version 2 of the GNU Lesser General Public
9 * License as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
25 #include <string.h> /* memset() */
26 #include <stdlib.h> /* alloca() */
29 #define s(x) /* strv debug */
30 #define p(x) /* poolv debug */
31 #define p2(x) /* poolv assertion checking */
33 /*#define MALLOC_CHECK*/
35 /*#define PROFILE_POOLV*/
50 struct timeval timeit_start;
52 static time_start(const char *desc)
54 gettimeofday(&timeit_start, NULL);
55 printf("starting: %s\n", desc);
58 static time_end(const char *desc)
63 gettimeofday(&end, NULL);
64 diff = end.tv_sec * 1000 + end.tv_usec/1000;
65 diff -= timeit_start.tv_sec * 1000 + timeit_start.tv_usec/1000;
66 printf("%s took %ld.%03ld seconds\n",
67 desc, diff / 1000, diff % 1000);
81 int status = mprobe(p);
85 printf("Memory underrun at %p\n", p);
88 printf("Memory overrun at %p\n", p);
91 printf("Double free %p\n", p);
96 #define MPROBE(x) checkmem((void *)(x))
103 typedef struct _MemChunkFreeNode {
104 struct _MemChunkFreeNode *next;
108 typedef struct _EMemChunk {
109 unsigned int blocksize; /* number of atoms in a block */
110 unsigned int atomsize; /* size of each atom */
111 GPtrArray *blocks; /* blocks of raw memory */
112 struct _MemChunkFreeNode *free;
117 * @atomcount: The number of atoms stored in a single malloc'd block of memory.
118 * @atomsize: The size of each allocation.
120 * Create a new memchunk header. Memchunks are an efficient way to allocate
121 * and deallocate identical sized blocks of memory quickly, and space efficiently.
123 * e_memchunks are effectively the same as gmemchunks, only faster (much), and
124 * they use less memory overhead for housekeeping.
126 * Return value: The new header.
128 MemChunk *e_memchunk_new(int atomcount, int atomsize)
130 MemChunk *m = g_malloc(sizeof(*m));
132 m->blocksize = atomcount;
133 m->atomsize = MAX(atomsize, sizeof(MemChunkFreeNode));
134 m->blocks = g_ptr_array_new();
144 * Allocate a new atom size block of memory from a memchunk.
146 void *e_memchunk_alloc(MemChunk *m)
156 mem = ((char *)f) + (f->atoms*m->atomsize);
159 m->free = m->free->next;
163 b = g_malloc(m->blocksize * m->atomsize);
164 g_ptr_array_add(m->blocks, b);
165 f = (MemChunkFreeNode *)&b[m->atomsize];
166 f->atoms = m->blocksize-1;
173 void *e_memchunk_alloc0(EMemChunk *m)
177 mem = e_memchunk_alloc(m);
178 memset(mem, 0, m->atomsize);
186 * @mem: Address of atom to free.
188 * Free a single atom back to the free pool of atoms in the given
192 e_memchunk_free(MemChunk *m, void *mem)
196 /* put the location back in the free list. If we knew if the preceeding or following
197 cells were free, we could merge the free nodes, but it doesn't really add much */
203 /* we could store the free list sorted - we could then do the above, and also
204 probably improve the locality of reference properties for the allocator */
205 /* and it would simplify some other algorithms at that, but slow this one down
213 * Clean out the memchunk buffers. Marks all allocated memory as free blocks,
214 * but does not give it back to the system. Can be used if the memchunk
215 * is to be used repeatedly.
218 e_memchunk_empty(MemChunk *m)
221 MemChunkFreeNode *f, *h = NULL;
223 for (i=0;i<m->blocks->len;i++) {
224 f = (MemChunkFreeNode *)m->blocks->pdata[i];
225 f->atoms = m->blocksize;
233 struct _cleaninfo *next;
236 int size; /* just so tree_search has it, sigh */
239 static int tree_compare(struct _cleaninfo *a, struct _cleaninfo *b)
241 if (a->base < b->base)
243 else if (a->base > b->base)
248 static int tree_search(struct _cleaninfo *a, char *mem)
250 if (a->base <= mem) {
251 if (mem < &a->base[a->size])
262 * Scan all empty blocks and check for blocks which can be free'd
263 * back to the system.
265 * This routine may take a while to run if there are many allocated
266 * memory blocks (if the total number of allocations is many times
267 * greater than atomcount).
270 e_memchunk_clean(MemChunk *m)
275 struct _cleaninfo *ci, *hi = NULL;
278 if (m->blocks->len == 0 || f == NULL)
281 /* first, setup the tree/list so we can map free block addresses to block addresses */
282 tree = g_tree_new((GCompareFunc)tree_compare);
283 for (i=0;i<m->blocks->len;i++) {
284 ci = alloca(sizeof(*ci));
286 ci->base = m->blocks->pdata[i];
287 ci->size = m->blocksize * m->atomsize;
288 g_tree_insert(tree, ci, ci);
293 /* now, scan all free nodes, and count them in their tree node */
295 ci = g_tree_search(tree, (GCompareFunc) tree_search, f);
297 ci->count += f->atoms;
299 g_warning("error, can't find free node in memory block\n");
304 /* if any nodes are all free, free & unlink them */
307 if (ci->count == m->blocksize) {
308 MemChunkFreeNode *prev = NULL;
312 if (tree_search (ci, (void *) f) == 0) {
313 /* prune this node from our free-node list */
315 prev->next = f->next;
325 g_ptr_array_remove_fast(m->blocks, ci->base);
331 g_tree_destroy(tree);
335 * e_memchunk_destroy:
338 * Free the memchunk header, and all associated memory.
341 e_memchunk_destroy(MemChunk *m)
348 for (i=0;i<m->blocks->len;i++)
349 g_free(m->blocks->pdata[i]);
350 g_ptr_array_free(m->blocks, TRUE);
354 typedef struct _MemPoolNode {
355 struct _MemPoolNode *next;
360 typedef struct _MemPoolThresholdNode {
361 struct _MemPoolThresholdNode *next;
362 } MemPoolThresholdNode;
364 #define ALIGNED_SIZEOF(t) ((sizeof (t) + G_MEM_ALIGN - 1) & -G_MEM_ALIGN)
366 typedef struct _EMemPool {
370 struct _MemPoolNode *blocks;
371 struct _MemPoolThresholdNode *threshold_blocks;
374 /* a pool of mempool header blocks */
375 static MemChunk *mempool_memchunk;
376 #ifdef G_THREADS_ENABLED
377 static GStaticMutex mempool_mutex = G_STATIC_MUTEX_INIT;
382 * @blocksize: The base blocksize to use for all system alocations.
383 * @threshold: If the allocation exceeds the threshold, then it is
384 * allocated separately and stored in a separate list.
385 * @flags: Alignment options: E_MEMPOOL_ALIGN_STRUCT uses native
386 * struct alignment, E_MEMPOOL_ALIGN_WORD aligns to 16 bits (2 bytes),
387 * and E_MEMPOOL_ALIGN_BYTE aligns to the nearest byte. The default
388 * is to align to native structures.
390 * Create a new mempool header. Mempools can be used to efficiently
391 * allocate data which can then be freed as a whole.
393 * Mempools can also be used to efficiently allocate arbitrarily
394 * aligned data (such as strings) without incurring the space overhead
395 * of aligning each allocation (which is not required for strings).
397 * However, each allocation cannot be freed individually, only all
402 MemPool *e_mempool_new(int blocksize, int threshold, EMemPoolFlags flags)
406 #ifdef G_THREADS_ENABLED
407 g_static_mutex_lock(&mempool_mutex);
409 if (mempool_memchunk == NULL) {
410 mempool_memchunk = e_memchunk_new(8, sizeof(MemPool));
412 pool = e_memchunk_alloc(mempool_memchunk);
413 #ifdef G_THREADS_ENABLED
414 g_static_mutex_unlock(&mempool_mutex);
416 if (threshold >= blocksize)
417 threshold = blocksize * 2 / 3;
418 pool->blocksize = blocksize;
419 pool->threshold = threshold;
421 pool->threshold_blocks = NULL;
423 switch (flags & E_MEMPOOL_ALIGN_MASK) {
424 case E_MEMPOOL_ALIGN_STRUCT:
426 pool->align = G_MEM_ALIGN-1;
428 case E_MEMPOOL_ALIGN_WORD:
431 case E_MEMPOOL_ALIGN_BYTE:
442 * Allocate a new data block in the mempool. Size will
443 * be rounded up to the mempool's alignment restrictions
446 void *e_mempool_alloc(MemPool *pool, register int size)
448 size = (size + pool->align) & (~(pool->align));
449 if (size>=pool->threshold) {
450 MemPoolThresholdNode *n;
452 n = g_malloc(ALIGNED_SIZEOF(*n) + size);
453 n->next = pool->threshold_blocks;
454 pool->threshold_blocks = n;
455 return (char *) n + ALIGNED_SIZEOF(*n);
457 register MemPoolNode *n;
460 if (n && n->free >= size) {
462 return (char *) n + ALIGNED_SIZEOF(*n) + n->free;
465 /* maybe we could do some sort of the free blocks based on size, but
466 it doubt its worth it at all */
468 n = g_malloc(ALIGNED_SIZEOF(*n) + pool->blocksize);
469 n->next = pool->blocks;
471 n->free = pool->blocksize - size;
472 return (char *) n + ALIGNED_SIZEOF(*n) + n->free;
476 char *e_mempool_strdup(EMemPool *pool, const char *str)
480 out = e_mempool_alloc(pool, strlen(str)+1);
489 * @freeall: Free all system allocated blocks as well.
491 * Flush used memory and mark allocated blocks as free.
493 * If @freeall is #TRUE, then all allocated blocks are free'd
494 * as well. Otherwise only blocks above the threshold are
495 * actually freed, and the others are simply marked as empty.
497 void e_mempool_flush(MemPool *pool, int freeall)
499 MemPoolThresholdNode *tn, *tw;
500 MemPoolNode *pw, *pn;
502 tw = pool->threshold_blocks;
508 pool->threshold_blocks = NULL;
521 pw->free = pool->blocksize;
531 * Free all memory associated with a mempool.
533 void e_mempool_destroy(MemPool *pool)
536 e_mempool_flush(pool, 1);
537 #ifdef G_THREADS_ENABLED
538 g_static_mutex_lock(&mempool_mutex);
540 e_memchunk_free(mempool_memchunk, pool);
541 #ifdef G_THREADS_ENABLED
542 g_static_mutex_unlock(&mempool_mutex);
552 #define STRV_UNPACKED ((unsigned char)(~0))
555 unsigned char length; /* how many entries we have (or the token STRV_UNPACKED) */
556 char data[1]; /* data follows */
559 struct _s_strv_string {
560 char *string; /* the string to output */
561 char *free; /* a string to free, if we referenced it */
564 struct _e_strvunpacked {
565 unsigned char type; /* we overload last to indicate this is unpacked */
566 MemPool *pool; /* pool of memory for strings */
567 struct _EStrv *source; /* if we were converted from a packed one, keep the source around for a while */
569 struct _s_strv_string strings[1]; /* the string array data follows */
574 * @size: The number of elements in the strv. Currently this is limited
577 * Create a new strv (string array) header. strv's can be used to
578 * create and work with arrays of strings that can then be compressed
579 * into a space-efficient static structure. This is useful
580 * where a number of strings are to be stored for lookup, and not
581 * generally edited afterwards.
583 * The size limit is currently 254 elements. This will probably not
584 * change as arrays of this size suffer significant performance
585 * penalties when looking up strings with high indices.
592 struct _e_strvunpacked *s;
596 s = g_malloc(sizeof(*s) + (size-1)*sizeof(s->strings[0]));
597 s(printf("new strv=%p, size = %d bytes\n", s, sizeof(*s) + (size-1)*sizeof(char *)));
598 s->type = STRV_UNPACKED;
602 memset(s->strings, 0, size*sizeof(s->strings[0]));
604 return (struct _EStrv *)s;
607 static struct _e_strvunpacked *
608 strv_unpack(struct _EStrv *strv)
610 struct _e_strvunpacked *s;
614 s(printf("unpacking\n"));
616 s = (struct _e_strvunpacked *)e_strv_new(strv->length);
618 for (i=0;i<s->length;i++) {
622 s->strings[i].string = p;
625 s->type = STRV_UNPACKED;
636 * Set a string array element by reference. The string
637 * is not copied until the array is packed.
639 * If @strv has been packed, then it is unpacked ready
640 * for more inserts, and should be packed again once finished with.
641 * The memory used by the original @strv is not freed until
642 * the new strv is packed, or freed itself.
644 * Return value: A new EStrv if the strv has already
645 * been packed, otherwise @strv.
648 e_strv_set_ref(struct _EStrv *strv, int index, char *str)
650 struct _e_strvunpacked *s;
652 s(printf("set ref %d '%s'\nawkmeharder: %s\n ", index, str, str));
654 if (strv->length != STRV_UNPACKED)
655 s = strv_unpack(strv);
657 s = (struct _e_strvunpacked *)strv;
659 g_assert(index>=0 && index < s->length);
661 s->strings[index].string = str;
663 return (struct _EStrv *)s;
667 * e_strv_set_ref_free:
672 * Set a string by reference, similar to set_ref, but also
673 * free the string when finished with it. The string
674 * is not copied until the strv is packed, and not at
675 * all if the index is overwritten.
677 * Return value: @strv if already unpacked, otherwise an packed
681 e_strv_set_ref_free(struct _EStrv *strv, int index, char *str)
683 struct _e_strvunpacked *s;
685 s(printf("set ref %d '%s'\nawkmeevenharder: %s\n ", index, str, str));
687 if (strv->length != STRV_UNPACKED)
688 s = strv_unpack(strv);
690 s = (struct _e_strvunpacked *)strv;
692 g_assert(index>=0 && index < s->length);
694 s->strings[index].string = str;
695 if (s->strings[index].free)
696 g_free(s->strings[index].free);
697 s->strings[index].free = str;
699 return (struct _EStrv *)s;
708 * Set a string array reference. The string @str is copied
709 * into the string array at location @index.
711 * If @strv has been packed, then it is unpacked ready
712 * for more inserts, and should be packed again once finished with.
714 * Return value: A new EStrv if the strv has already
715 * been packed, otherwise @strv.
718 e_strv_set(struct _EStrv *strv, int index, const char *str)
720 struct _e_strvunpacked *s;
722 s(printf("set %d '%s'\n", index, str));
724 if (strv->length != STRV_UNPACKED)
725 s = strv_unpack(strv);
727 s = (struct _e_strvunpacked *)strv;
729 g_assert(index>=0 && index < s->length);
732 s->pool = e_mempool_new(1024, 512, E_MEMPOOL_ALIGN_BYTE);
734 s->strings[index].string = e_mempool_alloc(s->pool, strlen(str)+1);
735 strcpy(s->strings[index].string, str);
737 return (struct _EStrv *)s;
744 * Pack the @strv into a space efficient structure for later lookup.
746 * All strings are packed into a single allocated block, separated
747 * by single \0 characters, together with a count byte.
752 e_strv_pack(struct _EStrv *strv)
754 struct _e_strvunpacked *s;
756 register char *src, *dst;
758 if (strv->length == STRV_UNPACKED) {
759 s = (struct _e_strvunpacked *)strv;
761 s(printf("packing string\n"));
764 for (i=0;i<s->length;i++)
765 len += s->strings[i].string?strlen(s->strings[i].string)+1:1;
767 strv = g_malloc(sizeof(*strv) + len);
768 s(printf("allocating strv=%p, size = %d\n", strv, sizeof(*strv)+len));
769 strv->length = s->length;
771 for (i=0;i<s->length;i++) {
772 if ((src = s->strings[i].string)) {
773 while ((*dst++ = *src++))
779 e_strv_destroy((struct _EStrv *)s);
789 * Retrieve a string by index. This function works
790 * identically on both packed and unpacked strv's, although
791 * may be much slower on a packed strv.
796 e_strv_get(struct _EStrv *strv, int index)
798 struct _e_strvunpacked *s;
801 if (strv->length != STRV_UNPACKED) {
802 g_assert(index>=0 && index < strv->length);
811 s = (struct _e_strvunpacked *)strv;
812 g_assert(index>=0 && index < s->length);
813 return s->strings[index].string?s->strings[index].string:"";
821 * Free a strv and all associated memory. Works on packed
822 * or unpacked strv's.
825 e_strv_destroy(struct _EStrv *strv)
827 struct _e_strvunpacked *s;
830 s(printf("freeing strv\n"));
832 if (strv->length == STRV_UNPACKED) {
833 s = (struct _e_strvunpacked *)strv;
835 e_mempool_destroy(s->pool);
837 e_strv_destroy(s->source);
838 for (i=0;i<s->length;i++) {
839 if (s->strings[i].free)
840 g_free(s->strings[i].free);
844 s(printf("freeing strv=%p\n", strv));
851 /* string pool stuff */
854 garbage collection, using the following technique:
855 Create a memchunk for each possible size of poolv, and allocate every poolv from those
856 To garbage collect, scan all memchunk internally, ignoring any free areas (or mark each
857 poolv when freeing it - set length 0?), and find out which strings are not anywhere,
861 Just keep a refcount in the hashtable, instead of duplicating the key pointer.
863 either would also require a free for the mempool, so ignore it for now */
865 /*#define POOLV_REFCNT*/ /* Define to enable refcounting code that does
866 automatic garbage collection of unused strings */
868 static GHashTable *poolv_pool = NULL;
869 static EMemPool *poolv_mempool = NULL;
872 static GPtrArray *poolv_table = NULL;
876 static gulong poolv_hits = 0;
877 static gulong poolv_misses = 0;
878 static unsigned long poolv_mem, poolv_count;
881 #ifdef G_THREADS_ENABLED
882 static GStaticMutex poolv_mutex = G_STATIC_MUTEX_INIT;
886 unsigned char length;
891 * e_poolv_new: @size: The number of elements in the poolv, maximum of 254 elements.
893 * create a new poolv (string vector which shares a global string
894 * pool). poolv's can be used to work with arrays of strings which
895 * save memory by eliminating duplicated allocations of the same
898 * this is useful when you have a log of read-only strings that do not
899 * go away and are duplicated a lot (such as email headers).
901 * we should probably in the future ref count the strings contained in
902 * the hash table, but for now let's not.
904 * Return value: new pooled string vector
907 e_poolv_new(unsigned int size)
911 g_assert(size < 255);
913 poolv = g_malloc0(sizeof (*poolv) + (size - 1) * sizeof (char *));
914 poolv->length = size;
916 #ifdef G_THREADS_ENABLED
917 g_static_mutex_lock(&poolv_mutex);
920 poolv_pool = g_hash_table_new(g_str_hash, g_str_equal);
923 poolv_mempool = e_mempool_new(32 * 1024, 512, E_MEMPOOL_ALIGN_BYTE);
929 if (poolv_table == NULL)
930 poolv_table = g_ptr_array_new();
932 for (i=0;i<poolv_table->len;i++)
933 MPROBE(poolv_table->pdata[i]);
935 g_ptr_array_add(poolv_table, poolv);
939 #ifdef G_THREADS_ENABLED
940 g_static_mutex_unlock(&poolv_mutex);
943 p(printf("new poolv=%p\tsize=%d\n", poolv, sizeof(*poolv) + (size-1)*sizeof(char *)));
953 * @dest: destination pooled string vector
954 * @src: source pooled string vector
956 * Copy the contents of a pooled string vector
958 * Return value: @dest, which may be re-allocated if the strings
959 * are different lengths.
962 e_poolv_cpy(EPoolv *dest, const EPoolv *src)
970 p2(g_return_val_if_fail (dest != NULL, NULL));
971 p2(g_return_val_if_fail (src != NULL, NULL));
976 if (dest->length != src->length) {
977 e_poolv_destroy(dest);
978 dest = e_poolv_new(src->length);
982 #ifdef G_THREADS_ENABLED
983 g_static_mutex_lock(&poolv_mutex);
986 for (i=0;i<src->length;i++) {
988 if (g_hash_table_lookup_extended(poolv_pool, src->s[i], (void **)&key, (void **)&ref)) {
989 g_hash_table_insert(poolv_pool, key, (void *)(ref+1));
991 g_assert_not_reached();
996 /* unref the old ones */
997 for (i=0;i<dest->length;i++) {
999 if (g_hash_table_lookup_extended(poolv_pool, dest->s[i], (void **)&key, (void **)&ref)) {
1000 /* if ref == 1 free it */
1002 g_hash_table_insert(poolv_pool, key, (void *)(ref-1));
1004 g_assert_not_reached();
1008 #ifdef G_THREADS_ENABLED
1009 g_static_mutex_unlock(&poolv_mutex);
1013 memcpy(dest->s, src->s, src->length * sizeof (char *));
1018 #ifdef PROFILE_POOLV
1020 poolv_profile_update (void)
1022 static time_t last_time = 0;
1025 new_time = time (NULL);
1026 if (new_time - last_time < 5)
1029 printf("poolv profile: %lu hits, %lu misses: %d%% hit rate, memory: %lu, instances: %lu\n",
1030 poolv_hits, poolv_misses,
1031 (int)(100.0 * ((double) poolv_hits / (double) (poolv_hits + poolv_misses))),
1032 poolv_mem, poolv_count);
1034 last_time = new_time;
1040 * @poolv: pooled string vector
1041 * @index: index in vector of string
1042 * @str: string to set
1043 * @freeit: whether the caller is releasing its reference to the
1046 * Set a string vector reference. If the caller will no longer be
1047 * referencing the string, freeit should be TRUE. Otherwise, this
1048 * will duplicate the string if it is not found in the pool.
1050 * Return value: @poolv
1053 e_poolv_set (EPoolv *poolv, int index, char *str, int freeit)
1060 p2(g_return_val_if_fail (poolv != NULL, NULL));
1062 g_assert(index >=0 && index < poolv->length);
1066 p(printf("setting %d `%s'\n", index, str));
1070 if (poolv->s[index]) {
1071 if (g_hash_table_lookup_extended(poolv_pool, poolv->s[index], (void **)&key, (void **)&ref)) {
1073 g_hash_table_insert(poolv_pool, key, (void *)(ref-1));
1075 g_assert_not_reached();
1079 poolv->s[index] = NULL;
1083 #ifdef G_THREADS_ENABLED
1084 g_static_mutex_lock(&poolv_mutex);
1088 if (g_hash_table_lookup_extended(poolv_pool, str, (void **)&key, (void **)&ref)) {
1089 g_hash_table_insert(poolv_pool, key, (void *)(ref+1));
1090 poolv->s[index] = key;
1091 # ifdef PROFILE_POOLV
1093 poolv_profile_update ();
1096 # ifdef PROFILE_POOLV
1098 poolv_mem += strlen(str);
1099 poolv_profile_update ();
1101 poolv->s[index] = e_mempool_strdup(poolv_mempool, str);
1102 g_hash_table_insert(poolv_pool, poolv->s[index], (void *)1);
1105 #else /* !POOLV_REFCNT */
1106 if ((poolv->s[index] = g_hash_table_lookup(poolv_pool, str)) != NULL) {
1107 # ifdef PROFILE_POOLV
1109 poolv_profile_update ();
1112 # ifdef PROFILE_POOLV
1114 poolv_mem += strlen(str);
1115 poolv_profile_update ();
1117 poolv->s[index] = e_mempool_strdup(poolv_mempool, str);
1118 g_hash_table_insert(poolv_pool, poolv->s[index], poolv->s[index]);
1120 #endif /* !POOLV_REFCNT */
1122 #ifdef G_THREADS_ENABLED
1123 g_static_mutex_unlock(&poolv_mutex);
1134 * @poolv: pooled string vector
1135 * @index: index in vector of string
1137 * Retrieve a string by index. This could possibly just be a macro.
1139 * Since the pool is never freed, this string does not need to be
1140 * duplicated, but should not be modified.
1142 * Return value: string at that index.
1145 e_poolv_get(EPoolv *poolv, int index)
1147 g_assert(poolv != NULL);
1148 g_assert(index>= 0 && index < poolv->length);
1152 p(printf("get %d = `%s'\n", index, poolv->s[index]));
1154 return poolv->s[index]?poolv->s[index]:"";
1159 * @poolv: pooled string vector to free
1161 * Free a pooled string vector. This doesn't free the strings from
1162 * the vector, however.
1165 e_poolv_destroy(EPoolv *poolv)
1174 #ifdef G_THREADS_ENABLED
1175 g_static_mutex_lock(&poolv_mutex);
1179 for (i=0;i<poolv_table->len;i++)
1180 MPROBE(poolv_table->pdata[i]);
1182 g_ptr_array_remove_fast(poolv_table, poolv);
1185 for (i=0;i<poolv->length;i++) {
1187 if (g_hash_table_lookup_extended(poolv_pool, poolv->s[i], (void **)&key, (void **)&ref)) {
1188 /* if ref == 1 free it */
1190 g_hash_table_insert(poolv_pool, key, (void *)(ref-1));
1192 g_assert_not_reached();
1196 #ifdef G_THREADS_ENABLED
1197 g_static_mutex_unlock(&poolv_mutex);
1201 #ifdef PROFILE_POOLV
1209 #define CHUNK_SIZE (20)
1210 #define CHUNK_COUNT (32)
1223 s = strv_set(s, 1, "Testing 1");
1224 s = strv_set(s, 2, "Testing 2");
1225 s = strv_set(s, 3, "Testing 3");
1226 s = strv_set(s, 4, "Testing 4");
1227 s = strv_set(s, 5, "Testing 5");
1228 s = strv_set(s, 6, "Testing 7");
1231 printf("s[%d] = %s\n", i, strv_get(s, i));
1236 printf("packing ...\n");
1240 printf("s[%d] = %s\n", i, strv_get(s, i));
1243 printf("setting ...\n");
1245 s = strv_set_ref(s, 1, "Testing 1 x");
1248 printf("s[%d] = %s\n", i, strv_get(s, i));
1251 printf("packing ...\n");
1255 printf("s[%d] = %s\n", i, strv_get(s, i));
1261 time_start("Using memchunks");
1262 mc = memchunk_new(CHUNK_COUNT, CHUNK_SIZE);
1263 for (i=0;i<1000000;i++) {
1264 mem = memchunk_alloc(mc);
1266 memchunk_free(mc, mem);
1269 memchunk_destroy(mc);
1270 time_end("allocating 1000000 memchunks, freeing 500k");
1272 time_start("Using gmemchunks");
1273 gmc = g_mem_chunk_new("memchunk", CHUNK_SIZE, CHUNK_SIZE*CHUNK_COUNT, G_ALLOC_AND_FREE);
1274 for (i=0;i<1000000;i++) {
1275 mem = g_mem_chunk_alloc(gmc);
1277 g_mem_chunk_free(gmc, mem);
1280 g_mem_chunk_destroy(gmc);
1281 time_end("allocating 1000000 gmemchunks, freeing 500k");
1283 time_start("Using memchunks");
1284 mc = memchunk_new(CHUNK_COUNT, CHUNK_SIZE);
1285 for (i=0;i<1000000;i++) {
1286 mem = memchunk_alloc(mc);
1289 memchunk_destroy(mc);
1290 time_end("allocating 1000000 memchunks");
1292 time_start("Using gmemchunks");
1293 gmc = g_mem_chunk_new("memchunk", CHUNK_SIZE, CHUNK_COUNT*CHUNK_SIZE, G_ALLOC_ONLY);
1294 for (i=0;i<1000000;i++) {
1295 mem = g_mem_chunk_alloc(gmc);
1298 g_mem_chunk_destroy(gmc);
1299 time_end("allocating 1000000 gmemchunks");
1301 time_start("Using malloc");
1302 for (i=0;i<1000000;i++) {
1305 time_end("allocating 1000000 malloc");