Annotation of libelwix/src/mem.c, revision 1.8.56.1
1.1 misho 1: /*************************************************************************
2: * (C) 2012 AITNET ltd - Sofia/Bulgaria - <misho@elwix.org>
3: * by Michael Pounov <misho@openbsd-bg.org>
4: *
5: * $Author: misho $
1.8.56.1! misho 6: * $Id: mem.c,v 1.8 2017/11/30 13:46:27 misho Exp $
1.1 misho 7: *
8: **************************************************************************
9: The ELWIX and AITNET software is distributed under the following
10: terms:
11:
12: All of the documentation and software included in the ELWIX and AITNET
13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
14:
1.8.56.1! misho 15: Copyright 2004 - 2022
1.1 misho 16: by Michael Pounov <misho@elwix.org>. All rights reserved.
17:
18: Redistribution and use in source and binary forms, with or without
19: modification, are permitted provided that the following conditions
20: are met:
21: 1. Redistributions of source code must retain the above copyright
22: notice, this list of conditions and the following disclaimer.
23: 2. Redistributions in binary form must reproduce the above copyright
24: notice, this list of conditions and the following disclaimer in the
25: documentation and/or other materials provided with the distribution.
26: 3. All advertising materials mentioning features or use of this software
27: must display the following acknowledgement:
28: This product includes software developed by Michael Pounov <misho@elwix.org>
29: ELWIX - Embedded LightWeight unIX and its contributors.
30: 4. Neither the name of AITNET nor the names of its contributors
31: may be used to endorse or promote products derived from this software
32: without specific prior written permission.
33:
34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: SUCH DAMAGE.
45: */
46: #include "global.h"
47:
48:
49: mpool_t *elwix_mpool;
50:
51:
52: /*
53: * mpool_init() - Init memory pool
54: *
55: * @maxmem = If !=0 set maximum memory quota
56: * return: =NULL error or !=NULL new allocated pool
57: */
58: mpool_t *
59: mpool_init(u_long maxmem)
60: {
61: mpool_t *mp;
62: register int i;
63:
64: mp = malloc(sizeof(mpool_t));
65: if (!mp) {
66: LOGERR;
67: return NULL;
68: } else
69: memset(mp, 0, sizeof(mpool_t));
70:
71: pthread_mutex_init(&mp->pool_mtx, NULL);
72:
73: mp->pool_quota.max = maxmem;
74:
75: mpool_lock(mp);
76: for (i = 0; i < MEM_BUCKETS; i++) {
77: TAILQ_INIT(&mp->pool_active[i]);
78: TAILQ_INIT(&mp->pool_inactive[i]);
79: }
80: mpool_unlock(mp);
81:
82: return mp;
83: }
84:
85: /*
86: * mpool_destroy() - Destroy memory pool
87: *
88: * @mp = Memory pool
89: * return: none
90: */
91: void
92: mpool_destroy(mpool_t ** __restrict mp)
93: {
94: struct tagAlloc *m;
95: register int i;
96:
97: if (!mp && !*mp)
98: return;
99:
100: mpool_lock(*mp);
101:
102: for (i = 0; i < MEM_BUCKETS; i++) {
103: while ((m = TAILQ_FIRST(&(*mp)->pool_active[i]))) {
104: TAILQ_REMOVE(&(*mp)->pool_active[i], m, alloc_node);
105: if (m->alloc_mem)
106: free(m->alloc_mem);
107: free(m);
108: }
109: while ((m = TAILQ_FIRST(&(*mp)->pool_inactive[i]))) {
110: TAILQ_REMOVE(&(*mp)->pool_inactive[i], m, alloc_node);
111: if (m->alloc_mem)
112: free(m->alloc_mem);
113: free(m);
114: }
115: }
116:
117: mpool_unlock(*mp);
118: pthread_mutex_destroy(&(*mp)->pool_mtx);
119:
120: free(*mp);
121: *mp = NULL;
122: }
123:
124: /* ----------------------------------------------------------- */
125:
126: static inline long
127: BucketIndex(u_int size)
128: {
129: register long b;
130:
131: if (!size--)
132: return 0; /* min bucket position in array */
133:
134: for (b = MEM_MIN_BUCKET; b < MEM_MAX_BUCKET; b++)
135: if (!(size >> b))
136: break;
137:
138: return b - MEM_MIN_BUCKET; /* convert to bucket array index */
139: }
140:
141: static inline struct tagAlloc *
142: pullInactive(mpool_t * __restrict mp, int idx)
143: {
144: struct tagAlloc *m = NULL;
145:
146: /* must be locked pool before use this function */
147: if ((m = TAILQ_FIRST(&mp->pool_inactive[idx]))) {
148: TAILQ_REMOVE(&mp->pool_inactive[idx], m, alloc_node);
149: /* statistics */
150: mp->pool_calls.cache--;
151: mp->pool_bytes.cache -= mem_size(m);
152:
153: /* clear name */
154: *m->alloc_name = 0;
155: }
156:
157: return m;
158: }
159:
160: /*
161: * mpool_malloc() - Memory allocation
162: *
163: * @mp = Memory pool
164: * @size = Size
165: * @memname = Optional memory block name
166: * return: NULL error or !=NULL ok allocated memory
167: */
168: void *
169: mpool_malloc(mpool_t * __restrict mp, u_int size, const char *memname)
170: {
171: struct tagAlloc *m;
172: int idx;
173: u_int align;
174:
175: if (!mp) {
176: elwix_SetErr(EINVAL, "Pool not specified");
177: return NULL;
178: }
179: if (size > MEM_ALLOC_MAX) {
180: elwix_SetErr(ENOMEM, "Memory size is too large");
181: return NULL;
182: } else
183: size = (size + 3) & ~3; /* must align to 4 because needed room for sentinels */
184:
185: idx = BucketIndex(size);
186:
187: mpool_lock(mp);
188:
189: /* get memory from cache if exists */
190: if (!(m = pullInactive(mp, idx))) {
191: /* quota */
192: if (mp->pool_quota.max &&
193: (mp->pool_quota.curr + size) > mp->pool_quota.max) {
194: elwix_SetErr(ENOMEM, "Max.allocate memory quota has been reached");
195: mpool_unlock(mp);
196: return NULL;
197: }
198:
199: m = malloc(sizeof(struct tagAlloc));
200: if (!m) {
201: LOGERR;
202: mpool_unlock(mp);
203: return NULL;
204: } else
205: memset(m, 0, sizeof(struct tagAlloc));
206: }
207:
208: if (memname)
209: strlcpy(m->alloc_name, memname, sizeof m->alloc_name);
210:
211: if (!m->alloc_mem) {
212: align = 1 << (idx + MEM_MIN_BUCKET);
213: m->alloc_mem = malloc(align + 12); /* +12 sentinel bytes */
214: if (!m->alloc_mem) {
215: LOGERR;
216: free(m);
217: mpool_unlock(mp);
218: return NULL;
219: } else { /* quota */
220: mp->pool_quota.curr += size;
1.5 misho 221: mp->pool_quota.real += 1 << (idx + MEM_MIN_BUCKET);
1.1 misho 222: memset(m->alloc_mem, 0, align + 12);
223: }
224: }
225:
226: m->alloc_mem[0] = size / sizeof(u_int);
227: m->alloc_mem[1] = MEM_MAGIC_START;
228: m->alloc_mem[2 + size / sizeof(u_int)] = MEM_MAGIC_STOP;
229: TAILQ_INSERT_HEAD(&mp->pool_active[idx], m, alloc_node);
230: /* statistics */
231: mp->pool_calls.alloc++;
232: mp->pool_bytes.alloc += size;
233:
234: mpool_unlock(mp);
235: return mem_data(m, void*);
236: }
237:
238: /*
239: * mpool_realloc() Reallocate memory block with new size
240: *
241: * @mp = Memory pool
242: * @data = Allocated memory data
243: * @newsize = New size of memory block
244: * @memname = Optional new memory block name
245: * return: NULL error or !=NULL new reallocated memory block
246: */
247: void *
248: mpool_realloc(mpool_t * __restrict mp, void * __restrict data, u_int newsize, const char *memname)
249: {
250: int idx, oidx;
251: void *p;
1.6 misho 252: u_int osize;
1.1 misho 253:
254: /* if !data execute mpool_malloc() */
255: if (!data)
256: return mpool_malloc(mp, newsize, memname);
257:
258: if (!mp) {
259: elwix_SetErr(EINVAL, "Pool not specified");
260: return NULL;
261: }
262: /* check address range & sentinel */
263: if (MEM_BADADDR(data) || MEM_CORRUPT(data)) {
264: elwix_SetErr(EFAULT, "Corrupted memory address");
265: return NULL;
266: }
267: /* prepare new size */
268: if (newsize > MEM_ALLOC_MAX) {
269: elwix_SetErr(ENOMEM, "Memory size is too large");
270: return NULL;
271: }
272:
273: mpool_lock(mp);
274:
1.6 misho 275: osize = ((u_int*)data)[-2] * sizeof(u_int);
276: oidx = BucketIndex(osize);
277: newsize = (newsize + 3) & ~3; /* must align to 4 because needed room for sentinels */
278: idx = BucketIndex(newsize);
279:
1.1 misho 280: /* quota */
281: if (mp->pool_quota.max &&
282: (mp->pool_quota.curr + ((u_long) newsize - osize)) > mp->pool_quota.max) {
283: elwix_SetErr(ENOMEM, "Max.allocate memory quota has been reached");
284: mpool_unlock(mp);
285: return NULL;
286: }
287:
1.6 misho 288: if (oidx != idx) {
1.1 misho 289: mpool_unlock(mp);
1.6 misho 290: p = mpool_malloc(mp, newsize, memname);
291: if (!p)
292: return NULL;
1.1 misho 293:
1.7 misho 294: memcpy(p, data, MIN(osize, newsize));
1.6 misho 295: mpool_free(mp, data, 0);
1.8 misho 296: data = p;
1.6 misho 297: } else {
298: p = data;
1.1 misho 299:
1.6 misho 300: ((u_int*) p)[-2] = newsize / sizeof(u_int);
301: ((u_int*) p)[newsize / sizeof(u_int)] = MEM_MAGIC_STOP;
1.1 misho 302:
1.6 misho 303: mp->pool_bytes.alloc += (u_long) newsize - osize;
304: mp->pool_quota.curr += (u_long) newsize - osize;
1.1 misho 305:
1.6 misho 306: mpool_unlock(mp);
1.1 misho 307: }
308:
1.6 misho 309: return p;
1.1 misho 310: }
311:
312: /*
313: * mpool_purge() - Purge memory block cache and release resources
314: *
315: * @mp = Memory pool
316: * @atmost = Free at most in buckets
317: * return: -1 error or 0 ok
318: */
319: int
320: mpool_purge(mpool_t * __restrict mp, u_int atmost)
321: {
322: register int i, cx;
323: struct tagAlloc *m, *tmp;
324:
325: if (!mp) {
326: elwix_SetErr(EINVAL, "Pool not specified");
327: return -1;
328: }
329:
330: mpool_lock(mp);
331:
332: for (i = cx = 0; i < MEM_BUCKETS; cx = 0, i++) {
333: TAILQ_FOREACH_SAFE(m, &mp->pool_inactive[i], alloc_node, tmp) {
334: /* barrier for purge */
335: if (cx < atmost) {
336: cx++;
337: continue;
338: }
339:
340: TAILQ_REMOVE(&mp->pool_inactive[i], m, alloc_node);
341: /* statistics */
342: mp->pool_calls.cache--;
343: mp->pool_bytes.cache -= mem_size(m);
344:
345: mp->pool_calls.free++;
346: mp->pool_bytes.free += mem_size(m);
347: /* quota */
348: mp->pool_quota.curr -= mem_size(m);
1.5 misho 349: mp->pool_quota.real -= 1 << (i + MEM_MIN_BUCKET);
1.1 misho 350:
351: if (m->alloc_mem)
352: free(m->alloc_mem);
353: free(m);
354: }
355: }
356:
357: mpool_unlock(mp);
358: return 0;
359: }
360:
361: /*
362: * mpool_free() Free allocated memory with mpool_alloc()
363: *
364: * @mp = Memory pool
365: * @data = Allocated memory data
366: * @purge = if !=0 force release memory block
367: * return: <0 error or 0 ok released memory block
368: */
369: int
370: mpool_free(mpool_t * __restrict mp, void * __restrict data, int purge)
371: {
372: int idx;
373: struct tagAlloc *m, *tmp;
374:
1.4 misho 375: if (!data)
376: return 0;
1.1 misho 377: if (!mp) {
378: elwix_SetErr(EINVAL, "Pool not specified");
379: return -1;
380: }
381: /* check address range & sentinel */
382: assert(!MEM_BADADDR(data) && !MEM_CORRUPT(data));
383: if (MEM_BADADDR(data) || MEM_CORRUPT(data)) {
384: elwix_SetErr(EFAULT, "Corrupted memory address");
385: return -2;
386: } else
387: idx = BucketIndex(((u_int*)data)[-2] * sizeof(u_int));
388:
389: mpool_lock(mp);
390: TAILQ_FOREACH_SAFE(m, &mp->pool_active[idx], alloc_node, tmp)
391: if (mem_data(m, void*) == data) {
392: TAILQ_REMOVE(&mp->pool_active[idx], m, alloc_node);
393: /* statistics */
394: mp->pool_calls.alloc--;
395: mp->pool_bytes.alloc -= mem_size(m);
396:
397: if (!purge) {
398: TAILQ_INSERT_HEAD(&mp->pool_inactive[idx], m, alloc_node);
399: /* statistics */
400: mp->pool_calls.cache++;
401: mp->pool_bytes.cache += mem_size(m);
402: } else {
403: /* statistics */
404: mp->pool_calls.free++;
405: mp->pool_bytes.free += mem_size(m);
406: /* quota */
407: mp->pool_quota.curr -= mem_size(m);
1.5 misho 408: mp->pool_quota.real -= 1 << (idx + MEM_MIN_BUCKET);
1.1 misho 409:
410: if (m->alloc_mem)
411: free(m->alloc_mem);
412: free(m);
413: }
414: break;
415: }
416: mpool_unlock(mp);
417:
418: return 0;
419: }
420:
421: /*
422: * mpool_free2() Free allocated memory with mpool_alloc() by size and memory name
423: *
424: * @mp = Memory pool
425: * @size = Allocated memory data size
426: * @memname = Memory name
427: * @purge = if !=0 force release memory block
428: * return: <0 error or 0 ok released memory block
429: */
430: int
431: mpool_free2(mpool_t * __restrict mp, u_int size, const char *memname, int purge)
432: {
433: int idx;
434: struct tagAlloc *m, *tmp;
435:
436: if (!mp || !memname) {
437: elwix_SetErr(EINVAL, "Pool or memory name is not specified");
438: return -1;
439: } else
440: idx = BucketIndex(size);
441:
442: mpool_lock(mp);
443: TAILQ_FOREACH_SAFE(m, &mp->pool_active[idx], alloc_node, tmp)
444: if (!strcmp(m->alloc_name, memname)) {
445: TAILQ_REMOVE(&mp->pool_active[idx], m, alloc_node);
446: /* statistics */
447: mp->pool_calls.alloc--;
448: mp->pool_bytes.alloc -= mem_size(m);
449:
450: if (!purge) {
451: TAILQ_INSERT_HEAD(&mp->pool_inactive[idx], m, alloc_node);
452: /* statistics */
453: mp->pool_calls.cache++;
454: mp->pool_bytes.cache += mem_size(m);
455: } else {
456: /* statistics */
457: mp->pool_calls.free++;
458: mp->pool_bytes.free += mem_size(m);
459: /* quota */
460: mp->pool_quota.curr -= mem_size(m);
1.5 misho 461: mp->pool_quota.real -= 1 << (idx + MEM_MIN_BUCKET);
1.1 misho 462:
463: if (m->alloc_mem)
464: free(m->alloc_mem);
465: free(m);
466: }
467: break;
468: }
469: mpool_unlock(mp);
470:
471: return 0;
472: }
473:
474: /*
475: * mpool_strdup() - String duplicate
476: *
477: * @mp = Memory pool
478: * @str = String
479: * @memname = Memory name
480: * return: NULL error or !=NULL new string
481: */
482: char *
483: mpool_strdup(mpool_t * __restrict mp, const char *str, const char *memname)
484: {
485: char *s = NULL;
486: u_int len;
487:
488: if (!mp) {
489: elwix_SetErr(EINVAL, "Pool not specified");
490: return NULL;
491: }
492: if (!str) {
493: elwix_SetErr(EINVAL, "String is NULL");
494: return NULL;
495: } else
496: len = strlen(str) + 1;
497:
498: s = mpool_malloc(mp, len, memname);
499: if (!s)
500: return NULL;
501: else
502: memcpy(s, str, len);
503:
504: return s;
505: }
506:
507: /*
508: * mpool_getmembynam() Find allocated memory block by size and memory name
509: *
510: * @mp = Memory pool
511: * @size = Memory size
512: * @memname = Memory name
513: * return: NULL error or not found and !=NULL allocated memory
514: */
1.2 misho 515: struct tagAlloc *
1.1 misho 516: mpool_getmembynam(mpool_t * __restrict mp, u_int size, const char *memname)
517: {
518: int idx;
519: struct tagAlloc *m = NULL;
520:
521: if (!mp || !memname)
522: return NULL;
523:
524: idx = BucketIndex(size);
525: TAILQ_FOREACH(m, &mp->pool_active[idx], alloc_node)
526: if (!strcmp(m->alloc_name, memname))
527: break;
528:
529: return mem_data(m, void*);
530: }
531:
532: /*
533: * mpool_getsizebyaddr() - Get size of allocated memory block by address
534: *
535: * @addr = allocated memory from mpool_malloc()
536: * return: usable size of allocated memory block
537: */
1.2 misho 538: u_int
1.1 misho 539: mpool_getsizebyaddr(void * __restrict data)
540: {
541: if (mpool_chkaddr(data))
542: return 0;
543:
544: return (((u_int*) data)[-2] * sizeof(u_int));
545: }
546:
547: /*
548: * mpool_chkaddr() - Check validity of given address
549: *
550: * @data = allocated memory from mpool_malloc()
551: * return: -1 bad address, 1 corrupted address or 0 ok
552: */
1.2 misho 553: int
1.1 misho 554: mpool_chkaddr(void * __restrict data)
555: {
556: /* check address range */
557: if (MEM_BADADDR(data))
558: return -1;
559: /* check sentinel */
560: if (MEM_CORRUPT(data))
561: return 1;
562: /* data address is ok! */
563: return 0;
564: }
565:
566: /*
567: * mpool_setquota() - Change maximum memory quota
568: *
569: * @mp = Memory pool
570: * @maxmem = New max quota size
571: * return: old maximum memory quota size
572: */
1.2 misho 573: u_long
1.1 misho 574: mpool_setquota(mpool_t * __restrict mp, u_long maxmem)
575: {
576: u_long ret;
577:
578: if (!mp)
579: return 0;
580:
581: ret = mp->pool_quota.max;
582: mp->pool_quota.max = maxmem;
583:
584: /* if new max quota is less then current allocated memory,
585: * try to purge memory cache blocks
586: */
587: if (mp->pool_quota.max < mp->pool_quota.curr)
588: mpool_purge(mp, 0);
589:
590: return ret;
591: }
592:
593: /*
594: * mpool_getquota() - Get memory quota
595: *
596: * @mp = Memory pool
1.5 misho 597: * @currmem = Return current memory usage
598: * @realmem = Return current real memory usage
1.1 misho 599: * @maxmem = Return max quota size
600: * return: none
601: */
1.2 misho 602: void
1.5 misho 603: mpool_getquota(mpool_t * __restrict mp, u_long *currmem, u_long *realmem, u_long *maxmem)
1.1 misho 604: {
605: if (!mp)
606: return;
607:
608: if (maxmem)
609: *maxmem = mp->pool_quota.max;
1.5 misho 610: if (realmem)
611: *realmem = mp->pool_quota.real;
1.1 misho 612: if (currmem)
613: *currmem = mp->pool_quota.curr;
614: }
615:
616: /* ----------------------------------------------------------- */
617:
618: /*
619: * mpool_statistics() - Dump statistics from memory pool buckets
620: *
621: * @mp = Memory pool
622: * @cb = Export statistics to callback
1.8.56.1! misho 623: * return: -1 error or >0 bytes in data buffer
1.1 misho 624: */
1.8.56.1! misho 625: int
! 626: mpool_statistics(mpool_t * __restrict mp, mpool_stat_cb cb, void *data, u_int datlen)
1.1 misho 627: {
628: struct tagAlloc *m;
629: register int i, act, inact;
1.8.56.1! misho 630: int len = 0;
1.1 misho 631:
632: if (!mp || !cb)
1.8.56.1! misho 633: return -1;
1.1 misho 634:
635: for (i = act = inact = 0; i < MEM_BUCKETS; act = inact = 0, i++) {
636: TAILQ_FOREACH(m, &mp->pool_active[i], alloc_node)
637: act++;
638: TAILQ_FOREACH(m, &mp->pool_inactive[i], alloc_node)
639: inact++;
640:
1.8.56.1! misho 641: len += cb(1 << (i + MEM_MIN_BUCKET), act, inact, data, datlen);
1.1 misho 642: }
1.8.56.1! misho 643:
! 644: return len;
1.1 misho 645: }
646:
647: /* ----------------------------------------------------------- */
648:
649: /*
650: * mpool_xmalloc() - malloc wrapper
651: *
652: * @size = Size
653: * return: NULL error or !=NULL ok allocated memory
654: */
655: void *
656: mpool_xmalloc(size_t size)
657: {
658: return mpool_malloc(elwix_mpool, size, elwix_Prog);
659: }
660:
661: /*
662: * mpool_xcalloc() - calloc wrapper
663: *
664: * @num = number of elements
665: * @size = Size of element
666: * return: NULL error or !=NULL ok allocated memory
667: */
668: void *
669: mpool_xcalloc(size_t num, size_t size)
670: {
671: return mpool_malloc(elwix_mpool, num * size, elwix_Prog);
672: }
673:
674: /*
675: * mpool_xrealloc() - realloc wrapper
676: *
677: * @data = Allocated memory data
678: * @newsize = New size of memory block
679: * return: NULL error or !=NULL new reallocated memory block
680: */
681: void *
682: mpool_xrealloc(void * __restrict data, size_t newsize)
683: {
684: return mpool_realloc(elwix_mpool, data, newsize, elwix_Prog);
685: }
686:
687: /*
688: * mpool_xfree() - free wrapper
689: *
690: * @data = Allocated memory data
691: * return: none
692: */
693: void
694: mpool_xfree(void * __restrict data)
695: {
696: mpool_free(elwix_mpool, data, 0);
697: }
698:
699: /*
700: * mpool_xstrdup() - strdup wrapper
701: *
702: * @str = string
703: * return: =NULL error or !=NULL new allocated string
704: */
705: char *
706: mpool_xstrdup(const char *str)
707: {
708: return mpool_strdup(elwix_mpool, str, elwix_Prog);
709: }
1.5 misho 710:
711: /*
1.8.56.1! misho 712: * mpool_xstatistics() - elwix default memory pool statistics wrapper
1.5 misho 713: *
714: * @cb = Export statistics to callback
1.8.56.1! misho 715: * @data = data buffer
! 716: * @datlen = data buffer length
! 717: * return: >0 data in string buffer
1.5 misho 718: */
1.8.56.1! misho 719: int
! 720: mpool_xstatistics(mpool_stat_cb cb, void *data, u_int datlen)
1.5 misho 721: {
1.8.56.1! misho 722: return mpool_statistics(elwix_mpool, cb, data, datlen);
1.5 misho 723: }
724:
1.8.56.1! misho 725: static int
! 726: xdump_show(u_int size, u_int act, u_int inact, void *data, u_int datlen)
1.5 misho 727: {
728: if (!act && !inact)
1.8.56.1! misho 729: return 0; /* skip empty bucket */
1.5 misho 730:
731: if (size < 1024)
732: printf("\t\t* BUCKET %uB size, %u active, %u inactive\n",
733: size, act, inact);
734: else if (size < 1048576)
735: printf("\t\t* BUCKET %uKB size, %u active, %u inactive\n",
736: size / 1024, act, inact);
737: else
738: printf("\t\t* BUCKET %uMB size, %u active, %u inactive\n",
739: size / 1048576, act, inact);
1.8.56.1! misho 740:
! 741: return 0;
! 742: }
! 743:
! 744: static int
! 745: xdump_show2(u_int size, u_int act, u_int inact, void *data, u_int datlen)
! 746: {
! 747: char szStr[STRSIZ], *str = data;
! 748: int len = 0;
! 749:
! 750: if (!data || !datlen)
! 751: return 0; /* skip missing data buffer */
! 752: if (!act && !inact)
! 753: return 0; /* skip empty bucket */
! 754:
! 755: if (size < 1024)
! 756: len = snprintf(szStr, sizeof szStr, "\t\t* BUCKET %uB size, %u active, %u inactive\n",
! 757: size, act, inact);
! 758: else if (size < 1048576)
! 759: len = snprintf(szStr, sizeof szStr, "\t\t* BUCKET %uKB size, %u active, %u inactive\n",
! 760: size / 1024, act, inact);
! 761: else
! 762: len = snprintf(szStr, sizeof szStr, "\t\t* BUCKET %uMB size, %u active, %u inactive\n",
! 763: size / 1048576, act, inact);
! 764:
! 765: strlcat(str, szStr, datlen);
! 766: return len;
1.5 misho 767: }
768:
769: /*
1.6 misho 770: * mpool_dump() - Dump elwix memory pool statistics
1.5 misho 771: *
1.6 misho 772: * @mp = memory pool, if =NULL dump elwix default memory pool
773: * @fmt = prefix info format string
1.5 misho 774: * @... = argument(s)
775: * return: none
776: */
777: void
1.6 misho 778: mpool_dump(mpool_t * __restrict mp, const char *fmt, ...)
1.5 misho 779: {
780: va_list lst;
1.6 misho 781: mpool_t *p = mp ? mp : elwix_mpool;
1.5 misho 782:
783: if (fmt) {
784: va_start(lst, fmt);
785: vprintf(fmt, lst);
786: va_end(lst);
787: } else
788: printf("\n%s(%d)\n", __func__, __LINE__);
789:
790: printf("------------------------------------------------------------\n");
1.8.56.1! misho 791: printf( " ELWIX memory pool %p ::\n"
1.5 misho 792: "\t- quotas Current/Real/Max = %lu/%lu/%lu\n"
793: "\t- calls Alloc/Free/Cache = %lu/%lu/%lu\n"
794: "\t- bytes Alloc/Free/Cache = %lu/%lu/%lu\n"
1.8.56.1! misho 795: "\t- buckets :\n", mp,
1.6 misho 796: p->pool_quota.curr, p->pool_quota.real, p->pool_quota.max,
797: p->pool_calls.alloc, p->pool_calls.free, p->pool_calls.cache,
798: p->pool_bytes.alloc, p->pool_bytes.free, p->pool_bytes.cache);
1.5 misho 799:
1.8.56.1! misho 800: mpool_statistics(p, xdump_show, NULL, 0);
1.5 misho 801: printf("------------------------------------------------------------\n");
802: }
803:
1.8.56.1! misho 804: /*
! 805: * mpool_dump2() - Dump elwix memory pool statistics to string
! 806: *
! 807: * @mp = memory pool, if =NULL dump elwix default memory pool
! 808: * @str = string buffer
! 809: * @strlen = string buffer length
! 810: * return: >0 data in string buffer
! 811: */
! 812: int
! 813: mpool_dump2(mpool_t * __restrict mp, char *str, int strlen)
! 814: {
! 815: int len;
! 816: mpool_t *p = mp ? mp : elwix_mpool;
! 817:
! 818: len = snprintf(str, strlen,
! 819: "------------------------------------------------------------\n");
! 820: len += snprintf(str + len, strlen - len, " ELWIX memory pool %p ::\n"
! 821: "\t- quotas Current/Real/Max = %lu/%lu/%lu\n"
! 822: "\t- calls Alloc/Free/Cache = %lu/%lu/%lu\n"
! 823: "\t- bytes Alloc/Free/Cache = %lu/%lu/%lu\n"
! 824: "\t- buckets :\n", mp,
! 825: p->pool_quota.curr, p->pool_quota.real, p->pool_quota.max,
! 826: p->pool_calls.alloc, p->pool_calls.free, p->pool_calls.cache,
! 827: p->pool_bytes.alloc, p->pool_bytes.free, p->pool_bytes.cache);
! 828: len += mpool_statistics(p, xdump_show2, str + len, strlen - len);
! 829: len += snprintf(str + len, strlen - len,
! 830: "------------------------------------------------------------\n");
! 831:
! 832: return len;
! 833: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>