Annotation of src/usr.bin/systat/malloc.c, Revision 1.1
1.1 ! canacar 1: /* $OpenBSD$ */
! 2: /*
! 3: * Copyright (c) 2008 Can Erkin Acar <canacar@openbsd.org>
! 4: *
! 5: * Permission to use, copy, modify, and distribute this software for any
! 6: * purpose with or without fee is hereby granted, provided that the above
! 7: * copyright notice and this permission notice appear in all copies.
! 8: *
! 9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 16: */
! 17:
! 18: #include <sys/types.h>
! 19: #include <sys/param.h>
! 20: #include <sys/sysctl.h>
! 21: #include <sys/malloc.h>
! 22: #include <errno.h>
! 23: #include <stdlib.h>
! 24: #include <string.h>
! 25:
! 26: #include "systat.h"
! 27:
! 28: void print_types(void);
! 29: void print_buckets(void);
! 30: int read_types(void);
! 31: int read_buckets(void);
! 32: void sort_types(void);
! 33: int select_types(void);
! 34: int select_buckets(void);
! 35: void showtype(int k);
! 36: void showbucket(int k);
! 37:
! 38:
! 39: /* qsort callbacks */
! 40: int sort_tname_callback(const void *s1, const void *s2);
! 41: int sort_treq_callback(const void *s1, const void *s2);
! 42: int sort_inuse_callback(const void *s1, const void *s2);
! 43: int sort_memuse_callback(const void *s1, const void *s2);
! 44:
! 45: #define MAX_BUCKETS 16
! 46:
! 47: struct type_info {
! 48: const char *name;
! 49: struct kmemstats stats;
! 50: char buckets[MAX_BUCKETS];
! 51: };
! 52:
! 53:
! 54: struct type_info types[M_LAST];
! 55:
! 56: struct kmembuckets buckets[MAX_BUCKETS];
! 57: int bucket_sizes[MAX_BUCKETS];
! 58:
! 59: int num_types = 0;
! 60: int num_buckets = 0;
! 61:
! 62: /*
! 63: * These names are defined in <sys/malloc.h>.
! 64: */
! 65: const char *kmemnames[] = INITKMEMNAMES;
! 66:
! 67: field_def fields_malloc[] = {
! 68: {"TYPE", 14, 32, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
! 69: {"INUSE", 6, 16, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
! 70: {"MEMUSE", 6, 16, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
! 71: {"HIGHUSE", 6, 16, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
! 72: {"LIMIT", 6, 16, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
! 73: {"REQUESTS", 8, 16, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
! 74: {"TYPE LIMIT", 5, 12, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
! 75: {"KERN LIMIT", 5, 12, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
! 76: {"BUCKETS", MAX_BUCKETS, MAX_BUCKETS, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
! 77:
! 78: {"BUCKET", 8, 8, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
! 79: {"REQUESTS", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
! 80: {"INUSE", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
! 81: {"FREE", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
! 82: {"HIWAT", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
! 83: {"COULDFREE", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
! 84: };
! 85:
! 86:
! 87: #define FIELD_ADDR(x) (&fields_malloc[x])
! 88:
! 89: #define FLD_TYPE_NAME FIELD_ADDR(0)
! 90: #define FLD_TYPE_INUSE FIELD_ADDR(1)
! 91: #define FLD_TYPE_MEMUSE FIELD_ADDR(2)
! 92: #define FLD_TYPE_HIGHUSE FIELD_ADDR(3)
! 93: #define FLD_TYPE_LIMIT FIELD_ADDR(4)
! 94: #define FLD_TYPE_REQUESTS FIELD_ADDR(5)
! 95: #define FLD_TYPE_TLIMIT FIELD_ADDR(6)
! 96: #define FLD_TYPE_KLIMIT FIELD_ADDR(7)
! 97: #define FLD_TYPE_SIZES FIELD_ADDR(8)
! 98:
! 99: #define FLD_BUCKET_SIZE FIELD_ADDR(9)
! 100: #define FLD_BUCKET_REQUESTS FIELD_ADDR(10)
! 101: #define FLD_BUCKET_INUSE FIELD_ADDR(11)
! 102: #define FLD_BUCKET_FREE FIELD_ADDR(12)
! 103: #define FLD_BUCKET_HIWAT FIELD_ADDR(13)
! 104: #define FLD_BUCKET_COULDFREE FIELD_ADDR(14)
! 105:
! 106:
! 107:
! 108: /* Define views */
! 109: field_def *view_malloc_0[] = {
! 110: FLD_TYPE_NAME, FLD_TYPE_INUSE, FLD_TYPE_MEMUSE,
! 111: FLD_TYPE_HIGHUSE, FLD_TYPE_LIMIT, FLD_TYPE_REQUESTS,
! 112: FLD_TYPE_TLIMIT, FLD_TYPE_KLIMIT, FLD_TYPE_SIZES, NULL
! 113: };
! 114:
! 115: field_def *view_malloc_1[] = {
! 116: FLD_BUCKET_SIZE, FLD_BUCKET_REQUESTS, FLD_BUCKET_INUSE,
! 117: FLD_BUCKET_FREE, FLD_BUCKET_HIWAT, FLD_BUCKET_COULDFREE, NULL
! 118: };
! 119:
! 120: order_type type_order_list[] = {
! 121: {"name", "name", 'N', sort_tname_callback},
! 122: {"inuse", "in use", 'U', sort_inuse_callback},
! 123: {"memuse", "mem use", 'S', sort_memuse_callback},
! 124: {"requests", "requests", 'Q', sort_treq_callback},
! 125: {NULL, NULL, 0, NULL}
! 126: };
! 127:
! 128: /* Define view managers */
! 129: struct view_manager types_mgr = {
! 130: "Types", select_types, read_types, sort_types, print_header,
! 131: print_types, keyboard_callback, type_order_list, type_order_list
! 132: };
! 133:
! 134: struct view_manager buckets_mgr = {
! 135: "Buckets", select_buckets, read_buckets, NULL, print_header,
! 136: print_buckets, keyboard_callback, NULL, NULL
! 137: };
! 138:
! 139: field_view views_malloc[] = {
! 140: {view_malloc_0, "malloc", '6', &types_mgr},
! 141: {view_malloc_1, "buckets", '7', &buckets_mgr},
! 142: {NULL, NULL, 0, NULL}
! 143: };
! 144:
! 145:
! 146: int
! 147: sort_tname_callback(const void *s1, const void *s2)
! 148: {
! 149: struct type_info *t1, *t2;
! 150: t1 = (struct type_info *)s1;
! 151: t2 = (struct type_info *)s2;
! 152:
! 153: return strcmp(t1->name, t2->name) * sortdir;
! 154: }
! 155:
! 156: int
! 157: sort_treq_callback(const void *s1, const void *s2)
! 158: {
! 159: struct type_info *t1, *t2;
! 160: t1 = (struct type_info *)s1;
! 161: t2 = (struct type_info *)s2;
! 162:
! 163: if (t1->stats.ks_calls < t2->stats.ks_calls)
! 164: return sortdir;
! 165: if (t1->stats.ks_calls > t2->stats.ks_calls)
! 166: return -sortdir;
! 167:
! 168: return sort_tname_callback(s1, s2);
! 169: }
! 170:
! 171: int
! 172: sort_inuse_callback(const void *s1, const void *s2)
! 173: {
! 174: struct type_info *t1, *t2;
! 175: t1 = (struct type_info *)s1;
! 176: t2 = (struct type_info *)s2;
! 177:
! 178: if (t1->stats.ks_inuse < t2->stats.ks_inuse)
! 179: return sortdir;
! 180: if (t1->stats.ks_inuse > t2->stats.ks_inuse)
! 181: return -sortdir;
! 182:
! 183: return sort_tname_callback(s1, s2);
! 184: }
! 185:
! 186: int
! 187: sort_memuse_callback(const void *s1, const void *s2)
! 188: {
! 189: struct type_info *t1, *t2;
! 190: t1 = (struct type_info *)s1;
! 191: t2 = (struct type_info *)s2;
! 192:
! 193: if (t1->stats.ks_memuse < t2->stats.ks_memuse)
! 194: return sortdir;
! 195: if (t1->stats.ks_memuse > t2->stats.ks_memuse)
! 196: return -sortdir;
! 197:
! 198: return sort_tname_callback(s1, s2);
! 199: }
! 200:
! 201:
! 202: void
! 203: sort_types(void)
! 204: {
! 205: order_type *ordering;
! 206:
! 207: if (curr_mgr == NULL)
! 208: return;
! 209:
! 210: ordering = curr_mgr->order_curr;
! 211:
! 212: if (ordering == NULL)
! 213: return;
! 214: if (ordering->func == NULL)
! 215: return;
! 216: if (num_types <= 0)
! 217: return;
! 218:
! 219: mergesort(types, num_types, sizeof(struct type_info), ordering->func);
! 220: }
! 221:
! 222: int
! 223: select_types(void)
! 224: {
! 225: num_disp = num_types;
! 226: return (0);
! 227: }
! 228:
! 229: int
! 230: select_buckets(void)
! 231: {
! 232: num_disp = num_buckets;
! 233: return (0);
! 234: }
! 235:
! 236: int
! 237: read_buckets(void)
! 238: {
! 239: int mib[4];
! 240: char buf[BUFSIZ], *bufp, *ap;
! 241: const char *errstr;
! 242: size_t siz;
! 243:
! 244: mib[0] = CTL_KERN;
! 245: mib[1] = KERN_MALLOCSTATS;
! 246: mib[2] = KERN_MALLOC_BUCKETS;
! 247:
! 248: siz = sizeof(buf);
! 249: num_buckets = 0;
! 250:
! 251: if (sysctl(mib, 3, buf, &siz, NULL, 0) < 0) {
! 252: error("sysctl(kern.malloc.buckets): %s", strerror(errno));
! 253: return (-1);
! 254: }
! 255:
! 256: bufp = buf;
! 257: mib[2] = KERN_MALLOC_BUCKET;
! 258: siz = sizeof(struct kmembuckets);
! 259:
! 260: while ((ap = strsep(&bufp, ",")) != NULL) {
! 261: if (num_buckets >= MAX_BUCKETS)
! 262: break;
! 263: bucket_sizes[num_buckets] = strtonum(ap, 0, INT_MAX, &errstr);
! 264: if (errstr) {
! 265: error("strtonum(%s): %s", ap, errstr);
! 266: return (-1);
! 267: }
! 268: mib[3] = bucket_sizes[num_buckets];
! 269: if (sysctl(mib, 4, &buckets[num_buckets], &siz,
! 270: NULL, 0) < 0) {
! 271: error("sysctl(kern.malloc.bucket.%d): %s",
! 272: mib[3], strerror(errno));
! 273: return (-1);
! 274: }
! 275: num_buckets++;
! 276: }
! 277:
! 278: return (0);
! 279: }
! 280:
! 281: int
! 282: read_types(void)
! 283: {
! 284: struct type_info *ti;
! 285: int i, j, k, mib[4];
! 286: size_t siz;
! 287:
! 288: bzero(types, sizeof(types));
! 289: ti = types;
! 290: siz = sizeof(struct kmemstats);
! 291:
! 292: num_types = 0;
! 293:
! 294: for (i = 0; i < M_LAST; i++) {
! 295: mib[0] = CTL_KERN;
! 296: mib[1] = KERN_MALLOCSTATS;
! 297: mib[2] = KERN_MALLOC_KMEMSTATS;
! 298: mib[3] = i;
! 299:
! 300: /*
! 301: * Skip errors -- these are presumed to be unallocated
! 302: * entries.
! 303: */
! 304: if (sysctl(mib, 4, &ti->stats, &siz, NULL, 0) < 0)
! 305: continue;
! 306:
! 307: if (ti->stats.ks_calls == 0)
! 308: continue;
! 309:
! 310: ti->name = kmemnames[i];
! 311: j = 1 << MINBUCKET;
! 312:
! 313: for (k = 0; k < MAX_BUCKETS; k++, j <<= 1)
! 314: ti->buckets[k] = (ti->stats.ks_size & j) ? '|' : '.';
! 315:
! 316: ti++;
! 317: num_types++;
! 318: }
! 319:
! 320: return (0);
! 321: }
! 322:
! 323:
! 324: void
! 325: print_types(void)
! 326: {
! 327: int n, count = 0;
! 328:
! 329: for (n = dispstart; n < num_disp; n++) {
! 330: showtype(n);
! 331: count++;
! 332: if (maxprint > 0 && count >= maxprint)
! 333: break; }
! 334: }
! 335:
! 336: void
! 337: print_buckets(void)
! 338: {
! 339: int n, count = 0;
! 340:
! 341: for (n = dispstart; n < num_disp; n++) {
! 342: showbucket(n);
! 343: count++;
! 344: if (maxprint > 0 && count >= maxprint)
! 345: break;
! 346: }
! 347: }
! 348:
! 349: int
! 350: initmalloc(void)
! 351: {
! 352: field_view *v;
! 353:
! 354: for (v = views_malloc; v->name != NULL; v++)
! 355: add_view(v);
! 356:
! 357: read_buckets();
! 358: read_types();
! 359:
! 360: return(0);
! 361: }
! 362:
! 363: void
! 364: showbucket(int k)
! 365: {
! 366: struct kmembuckets *kp = buckets + k;
! 367:
! 368: if (k < 0 || k >= num_buckets)
! 369: return;
! 370:
! 371: print_fld_size(FLD_BUCKET_SIZE, bucket_sizes[k]);
! 372: print_fld_size(FLD_BUCKET_INUSE, kp->kb_total - kp->kb_totalfree);
! 373: print_fld_size(FLD_BUCKET_FREE, kp->kb_totalfree);
! 374: print_fld_size(FLD_BUCKET_REQUESTS, kp->kb_calls);
! 375: print_fld_size(FLD_BUCKET_HIWAT, kp->kb_highwat);
! 376: print_fld_size(FLD_BUCKET_COULDFREE, kp->kb_couldfree);
! 377:
! 378: end_line();
! 379: }
! 380:
! 381:
! 382: void
! 383: showtype(int k)
! 384: {
! 385: struct type_info *t = types + k;
! 386:
! 387: if (k < 0 || k >= num_types)
! 388: return;
! 389:
! 390:
! 391: print_fld_str(FLD_TYPE_NAME, t->name ? t->name : "undefined");
! 392: print_fld_size(FLD_TYPE_INUSE, t->stats.ks_inuse);
! 393: print_fld_size(FLD_TYPE_MEMUSE, t->stats.ks_memuse);
! 394: print_fld_size(FLD_TYPE_HIGHUSE, t->stats.ks_maxused);
! 395: print_fld_size(FLD_TYPE_LIMIT, t->stats.ks_limit);
! 396: print_fld_size(FLD_TYPE_REQUESTS, t->stats.ks_calls);
! 397: print_fld_size(FLD_TYPE_TLIMIT, t->stats.ks_limblocks);
! 398: print_fld_size(FLD_TYPE_KLIMIT, t->stats.ks_mapblocks);
! 399: print_fld_str(FLD_TYPE_SIZES, t->buckets);
! 400:
! 401: end_line();
! 402: }