[BACK]Return to malloc.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / systat

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: }