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

Annotation of src/usr.bin/systat/cpu.c, Revision 1.1

1.1     ! reyk        1: /*     $OpenBSD$       */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2013 Reyk Floeter <reyk@openbsd.org>
        !             5:  * Copyright (c) 2001, 2007 Can Erkin Acar <canacar@openbsd.org>
        !             6:  *
        !             7:  * Permission to use, copy, modify, and distribute this software for any
        !             8:  * purpose with or without fee is hereby granted, provided that the above
        !             9:  * copyright notice and this permission notice appear in all copies.
        !            10:  *
        !            11:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            12:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            13:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            14:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            15:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            16:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            17:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            18:  */
        !            19:
        !            20: /* CPU percentages() function from usr.bin/top/util.c:
        !            21:  *
        !            22:  *  Top users/processes display for Unix
        !            23:  *  Version 3
        !            24:  *
        !            25:  * Copyright (c) 1984, 1989, William LeFebvre, Rice University
        !            26:  * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University
        !            27:  *
        !            28:  * Redistribution and use in source and binary forms, with or without
        !            29:  * modification, are permitted provided that the following conditions
        !            30:  * are met:
        !            31:  * 1. Redistributions of source code must retain the above copyright
        !            32:  *    notice, this list of conditions and the following disclaimer.
        !            33:  * 2. Redistributions in binary form must reproduce the above copyright
        !            34:  *    notice, this list of conditions and the following disclaimer in the
        !            35:  *    documentation and/or other materials provided with the distribution.
        !            36:  *
        !            37:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            38:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            39:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            40:  * IN NO EVENT SHALL THE AUTHOR OR HIS EMPLOYER BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            41:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            42:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            43:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            44:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            45:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            46:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            47:  */
        !            48:
        !            49: #include <sys/param.h>
        !            50: #include <sys/dkstat.h>
        !            51: #include <sys/sysctl.h>
        !            52:
        !            53: #include <stdlib.h>
        !            54: #include <stdint.h>
        !            55: #include <string.h>
        !            56: #include <unistd.h>
        !            57: #include "systat.h"
        !            58:
        !            59: void            print_cpu(void);
        !            60: int             read_cpu(void);
        !            61: int             select_cpu(void);
        !            62: static void     cpu_info(void);
        !            63: static void     print_fld_percentage(field_def *, double);
        !            64: static int      percentages(int, int64_t *, int64_t *, int64_t *, int64_t *);
        !            65:
        !            66: field_def fields_cpu[] = {
        !            67:        { "CPU", 4, 8, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0 },
        !            68:        { "User", 10, 20, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0 },
        !            69:        { "Nice", 10, 20, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0 },
        !            70:        { "System", 10, 20, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0 },
        !            71:        { "Interrupt", 10, 20, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0 },
        !            72:        { "Idle", 10, 20, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0 },
        !            73: };
        !            74:
        !            75: #define FLD_CPU_CPU    FIELD_ADDR(fields_cpu, 0)
        !            76: #define FLD_CPU_INT    FIELD_ADDR(fields_cpu, 1)
        !            77: #define FLD_CPU_SYS    FIELD_ADDR(fields_cpu, 2)
        !            78: #define FLD_CPU_USR    FIELD_ADDR(fields_cpu, 3)
        !            79: #define FLD_CPU_NIC    FIELD_ADDR(fields_cpu, 4)
        !            80: #define FLD_CPU_IDLE   FIELD_ADDR(fields_cpu, 5)
        !            81:
        !            82: /* Define views */
        !            83: field_def *view_cpu_0[] = {
        !            84:        FLD_CPU_CPU,
        !            85:        FLD_CPU_INT, FLD_CPU_SYS, FLD_CPU_USR, FLD_CPU_NIC, FLD_CPU_IDLE
        !            86: };
        !            87:
        !            88: /* Define view managers */
        !            89: struct view_manager cpu_mgr = {
        !            90:        "cpu", select_cpu, read_cpu, NULL, print_header,
        !            91:        print_cpu, keyboard_callback, NULL, NULL
        !            92: };
        !            93:
        !            94: field_view views_cpu[] = {
        !            95:        { view_cpu_0, "cpu", 'C', &cpu_mgr },
        !            96:        { NULL, NULL, 0, NULL }
        !            97: };
        !            98:
        !            99: int      cpu_count;
        !           100: int64_t         *cpu_states;
        !           101: int64_t        **cpu_tm;
        !           102: int64_t        **cpu_old;
        !           103: int64_t        **cpu_diff;
        !           104:
        !           105: /*
        !           106:  * percentages(cnt, out, new, old, diffs) - calculate percentage change
        !           107:  * between array "old" and "new", putting the percentages in "out".
        !           108:  * "cnt" is size of each array and "diffs" is used for scratch space.
        !           109:  * The array "old" is updated on each call.
        !           110:  * The routine assumes modulo arithmetic.  This function is especially
        !           111:  * useful on BSD machines for calculating cpu state percentages.
        !           112:  */
        !           113: static int
        !           114: percentages(int cnt, int64_t *out, int64_t *new, int64_t *old, int64_t *diffs)
        !           115: {
        !           116:        int64_t change, total_change, *dp, half_total;
        !           117:        int i;
        !           118:
        !           119:        /* initialization */
        !           120:        total_change = 0;
        !           121:        dp = diffs;
        !           122:
        !           123:        /* calculate changes for each state and the overall change */
        !           124:        for (i = 0; i < cnt; i++) {
        !           125:                if ((change = *new - *old) < 0) {
        !           126:                        /* this only happens when the counter wraps */
        !           127:                        change = INT64_MAX - *old + *new;
        !           128:                }
        !           129:                total_change += (*dp++ = change);
        !           130:                *old++ = *new++;
        !           131:        }
        !           132:
        !           133:        /* avoid divide by zero potential */
        !           134:        if (total_change == 0)
        !           135:                total_change = 1;
        !           136:
        !           137:        /* calculate percentages based on overall change, rounding up */
        !           138:        half_total = total_change / 2l;
        !           139:        for (i = 0; i < cnt; i++)
        !           140:                *out++ = ((*diffs++ * 1000 + half_total) / total_change);
        !           141:
        !           142:        /* return the total in case the caller wants to use it */
        !           143:        return (total_change);
        !           144: }
        !           145:
        !           146: static void
        !           147: cpu_info(void)
        !           148: {
        !           149:        int      cpu_time_mib[] = { CTL_KERN, KERN_CPTIME2, 0 }, i;
        !           150:        int64_t *tmpstate;
        !           151:        size_t   size;
        !           152:
        !           153:        size = CPUSTATES * sizeof(int64_t);
        !           154:        for (i = 0; i < cpu_count; i++) {
        !           155:                cpu_time_mib[2] = i;
        !           156:                tmpstate = cpu_states + (CPUSTATES * i);
        !           157:                if (sysctl(cpu_time_mib, 3, cpu_tm[i], &size, NULL, 0) < 0)
        !           158:                        error("sysctl KERN_CPTIME2");
        !           159:                percentages(CPUSTATES, tmpstate, cpu_tm[i],
        !           160:                    cpu_old[i], cpu_diff[i]);
        !           161:        }
        !           162: }
        !           163:
        !           164: static void
        !           165: print_fld_percentage(field_def *fld, double val)
        !           166: {
        !           167:        if (fld == NULL)
        !           168:                return;
        !           169:
        !           170:        tb_start();
        !           171:        tbprintf(val >= 1000 ? "%4.0f%%" : "%4.1f%%", val / 10.);
        !           172:        print_fld_tb(fld);
        !           173:        tb_end();
        !           174: }
        !           175:
        !           176: int
        !           177: select_cpu(void)
        !           178: {
        !           179:        return (0);
        !           180: }
        !           181:
        !           182: int
        !           183: read_cpu(void)
        !           184: {
        !           185:        cpu_info();
        !           186:        num_disp = cpu_count;
        !           187:        return (0);
        !           188: }
        !           189:
        !           190: int
        !           191: initcpu(void)
        !           192: {
        !           193:        field_view      *v;
        !           194:        size_t           size = sizeof(cpu_count);
        !           195:        int              mib[2], i;
        !           196:
        !           197:        mib[0] = CTL_HW;
        !           198:        mib[1] = HW_NCPU;
        !           199:        if (sysctl(mib, 2, &cpu_count, &size, NULL, 0) == -1)
        !           200:                return (-1);
        !           201:        if ((cpu_states = calloc(cpu_count,
        !           202:            CPUSTATES * sizeof(int64_t))) == NULL)
        !           203:                return (-1);
        !           204:        if ((cpu_tm = calloc(cpu_count, sizeof(int64_t *))) == NULL ||
        !           205:            (cpu_old = calloc(cpu_count, sizeof(int64_t *))) == NULL ||
        !           206:            (cpu_diff = calloc(cpu_count, sizeof(int64_t *))) == NULL)
        !           207:                return (-1);
        !           208:        for (i = 0; i < cpu_count; i++) {
        !           209:                if ((cpu_tm[i] = calloc(CPUSTATES, sizeof(int64_t))) == NULL ||
        !           210:                    (cpu_old[i] = calloc(CPUSTATES, sizeof(int64_t))) == NULL ||
        !           211:                    (cpu_diff[i] = calloc(CPUSTATES, sizeof(int64_t))) == NULL)
        !           212:                        return (-1);
        !           213:        }
        !           214:
        !           215:        for (v = views_cpu; v->name != NULL; v++)
        !           216:                add_view(v);
        !           217:
        !           218:        read_cpu();
        !           219:
        !           220:        return(1);
        !           221: }
        !           222:
        !           223: #define ADD_EMPTY_LINE \
        !           224:        do {                                                            \
        !           225:                if (cur >= dispstart && cur < end)                      \
        !           226:                        end_line();                                     \
        !           227:                if (++cur >= end)                                       \
        !           228:                        return;                                         \
        !           229:        } while (0)
        !           230:
        !           231: #define ADD_LINE_CPU(v, cs) \
        !           232:        do {                                                            \
        !           233:                if (cur >= dispstart && cur < end) {                    \
        !           234:                        print_fld_size(FLD_CPU_CPU, (v));               \
        !           235:                        print_fld_percentage(FLD_CPU_INT, (cs[0]));     \
        !           236:                        print_fld_percentage(FLD_CPU_SYS, (cs[1]));     \
        !           237:                        print_fld_percentage(FLD_CPU_USR, (cs[2]));     \
        !           238:                        print_fld_percentage(FLD_CPU_NIC, (cs[3]));     \
        !           239:                        print_fld_percentage(FLD_CPU_IDLE, (cs[4]));    \
        !           240:                        end_line();                                     \
        !           241:                }                                                       \
        !           242:                if (++cur >= end)                                       \
        !           243:                        return;                                         \
        !           244:        } while (0)
        !           245:
        !           246: void
        !           247: print_cpu(void)
        !           248: {
        !           249:        time_t          tm;
        !           250:        int             cur = 0, c, i;
        !           251:        int             end = dispstart + maxprint;
        !           252:        int64_t         *states;
        !           253:        double          value[CPUSTATES];
        !           254:        tm = time(NULL);
        !           255:
        !           256:        if (end > num_disp)
        !           257:                end = num_disp;
        !           258:
        !           259:        for (c = 0; c < cpu_count; c++) {
        !           260:                states = cpu_states + (CPUSTATES * c);
        !           261:
        !           262:                for (i = 0; i < CPUSTATES; i++)
        !           263:                        value[i] = *states++;
        !           264:
        !           265:                ADD_LINE_CPU(c, value);
        !           266:        }
        !           267:
        !           268:        ADD_EMPTY_LINE;
        !           269: }