[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.7

1.7     ! cheloha     1: /*     $OpenBSD: cpu.c,v 1.6 2018/05/14 12:31:21 mpi Exp $     */
1.1       reyk        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:
1.4       deraadt    49: #include <sys/signal.h>
1.3       miod       50: #include <sys/sched.h>
1.1       reyk       51: #include <sys/sysctl.h>
                     52:
1.7     ! cheloha    53: #include <errno.h>
1.1       reyk       54: #include <stdlib.h>
                     55: #include <stdint.h>
                     56: #include <string.h>
                     57: #include <unistd.h>
                     58: #include "systat.h"
                     59:
                     60: void            print_cpu(void);
                     61: int             read_cpu(void);
                     62: int             select_cpu(void);
                     63: static void     cpu_info(void);
                     64: static void     print_fld_percentage(field_def *, double);
                     65: static int      percentages(int, int64_t *, int64_t *, int64_t *, int64_t *);
                     66:
                     67: field_def fields_cpu[] = {
                     68:        { "CPU", 4, 8, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0 },
                     69:        { "User", 10, 20, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0 },
                     70:        { "Nice", 10, 20, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0 },
                     71:        { "System", 10, 20, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0 },
1.6       mpi        72:        { "Spin", 10, 20, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0 },
1.1       reyk       73:        { "Interrupt", 10, 20, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0 },
                     74:        { "Idle", 10, 20, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0 },
                     75: };
                     76:
                     77: #define FLD_CPU_CPU    FIELD_ADDR(fields_cpu, 0)
1.6       mpi        78: #define FLD_CPU_USR    FIELD_ADDR(fields_cpu, 1)
                     79: #define FLD_CPU_NIC    FIELD_ADDR(fields_cpu, 2)
                     80: #define FLD_CPU_SYS    FIELD_ADDR(fields_cpu, 3)
                     81: #define FLD_CPU_SPIN   FIELD_ADDR(fields_cpu, 4)
                     82: #define FLD_CPU_INT    FIELD_ADDR(fields_cpu, 5)
                     83: #define FLD_CPU_IDLE   FIELD_ADDR(fields_cpu, 6)
1.1       reyk       84:
                     85: /* Define views */
                     86: field_def *view_cpu_0[] = {
1.6       mpi        87:        FLD_CPU_CPU, FLD_CPU_USR, FLD_CPU_NIC, FLD_CPU_SYS, FLD_CPU_SPIN,
                     88:        FLD_CPU_INT, FLD_CPU_IDLE, NULL
1.1       reyk       89: };
                     90:
                     91: /* Define view managers */
                     92: struct view_manager cpu_mgr = {
                     93:        "cpu", select_cpu, read_cpu, NULL, print_header,
                     94:        print_cpu, keyboard_callback, NULL, NULL
                     95: };
                     96:
                     97: field_view views_cpu[] = {
                     98:        { view_cpu_0, "cpu", 'C', &cpu_mgr },
                     99:        { NULL, NULL, 0, NULL }
                    100: };
                    101:
                    102: int      cpu_count;
1.7     ! cheloha   103: int     *cpu_online;
1.1       reyk      104: int64_t         *cpu_states;
                    105: int64_t        **cpu_tm;
                    106: int64_t        **cpu_old;
                    107: int64_t        **cpu_diff;
                    108:
                    109: /*
                    110:  * percentages(cnt, out, new, old, diffs) - calculate percentage change
                    111:  * between array "old" and "new", putting the percentages in "out".
                    112:  * "cnt" is size of each array and "diffs" is used for scratch space.
                    113:  * The array "old" is updated on each call.
                    114:  * The routine assumes modulo arithmetic.  This function is especially
                    115:  * useful on BSD machines for calculating cpu state percentages.
                    116:  */
                    117: static int
                    118: percentages(int cnt, int64_t *out, int64_t *new, int64_t *old, int64_t *diffs)
                    119: {
                    120:        int64_t change, total_change, *dp, half_total;
                    121:        int i;
                    122:
                    123:        /* initialization */
                    124:        total_change = 0;
                    125:        dp = diffs;
                    126:
                    127:        /* calculate changes for each state and the overall change */
                    128:        for (i = 0; i < cnt; i++) {
                    129:                if ((change = *new - *old) < 0) {
                    130:                        /* this only happens when the counter wraps */
                    131:                        change = INT64_MAX - *old + *new;
                    132:                }
                    133:                total_change += (*dp++ = change);
                    134:                *old++ = *new++;
                    135:        }
                    136:
                    137:        /* avoid divide by zero potential */
                    138:        if (total_change == 0)
                    139:                total_change = 1;
                    140:
                    141:        /* calculate percentages based on overall change, rounding up */
                    142:        half_total = total_change / 2l;
                    143:        for (i = 0; i < cnt; i++)
                    144:                *out++ = ((*diffs++ * 1000 + half_total) / total_change);
                    145:
                    146:        /* return the total in case the caller wants to use it */
                    147:        return (total_change);
                    148: }
                    149:
                    150: static void
                    151: cpu_info(void)
                    152: {
                    153:        int      cpu_time_mib[] = { CTL_KERN, KERN_CPTIME2, 0 }, i;
                    154:        int64_t *tmpstate;
                    155:        size_t   size;
                    156:
                    157:        size = CPUSTATES * sizeof(int64_t);
                    158:        for (i = 0; i < cpu_count; i++) {
                    159:                cpu_time_mib[2] = i;
                    160:                tmpstate = cpu_states + (CPUSTATES * i);
1.7     ! cheloha   161:                if (sysctl(cpu_time_mib, 3, cpu_tm[i], &size, NULL, 0) < 0) {
        !           162:                        if (errno != ENODEV)
        !           163:                                error("sysctl KERN_CPTIME2");
        !           164:                        cpu_online[i] = 0;
        !           165:                        continue;
        !           166:                }
        !           167:                cpu_online[i] = 1;
1.1       reyk      168:                percentages(CPUSTATES, tmpstate, cpu_tm[i],
                    169:                    cpu_old[i], cpu_diff[i]);
                    170:        }
                    171: }
                    172:
                    173: static void
                    174: print_fld_percentage(field_def *fld, double val)
                    175: {
                    176:        if (fld == NULL)
                    177:                return;
                    178:
                    179:        tb_start();
                    180:        tbprintf(val >= 1000 ? "%4.0f%%" : "%4.1f%%", val / 10.);
                    181:        print_fld_tb(fld);
                    182:        tb_end();
                    183: }
                    184:
                    185: int
                    186: select_cpu(void)
                    187: {
                    188:        return (0);
                    189: }
                    190:
                    191: int
                    192: read_cpu(void)
                    193: {
                    194:        cpu_info();
                    195:        num_disp = cpu_count;
                    196:        return (0);
                    197: }
                    198:
                    199: int
                    200: initcpu(void)
                    201: {
                    202:        field_view      *v;
                    203:        size_t           size = sizeof(cpu_count);
                    204:        int              mib[2], i;
                    205:
                    206:        mib[0] = CTL_HW;
                    207:        mib[1] = HW_NCPU;
                    208:        if (sysctl(mib, 2, &cpu_count, &size, NULL, 0) == -1)
                    209:                return (-1);
1.7     ! cheloha   210:        if ((cpu_online = calloc(cpu_count, sizeof(*cpu_online))) == NULL)
        !           211:                return (-1);
1.1       reyk      212:        if ((cpu_states = calloc(cpu_count,
                    213:            CPUSTATES * sizeof(int64_t))) == NULL)
                    214:                return (-1);
                    215:        if ((cpu_tm = calloc(cpu_count, sizeof(int64_t *))) == NULL ||
                    216:            (cpu_old = calloc(cpu_count, sizeof(int64_t *))) == NULL ||
                    217:            (cpu_diff = calloc(cpu_count, sizeof(int64_t *))) == NULL)
                    218:                return (-1);
                    219:        for (i = 0; i < cpu_count; i++) {
                    220:                if ((cpu_tm[i] = calloc(CPUSTATES, sizeof(int64_t))) == NULL ||
                    221:                    (cpu_old[i] = calloc(CPUSTATES, sizeof(int64_t))) == NULL ||
                    222:                    (cpu_diff[i] = calloc(CPUSTATES, sizeof(int64_t))) == NULL)
                    223:                        return (-1);
                    224:        }
                    225:
                    226:        for (v = views_cpu; v->name != NULL; v++)
                    227:                add_view(v);
                    228:
                    229:        read_cpu();
                    230:
                    231:        return(1);
                    232: }
                    233:
                    234: #define ADD_EMPTY_LINE \
                    235:        do {                                                            \
                    236:                if (cur >= dispstart && cur < end)                      \
                    237:                        end_line();                                     \
                    238:                if (++cur >= end)                                       \
                    239:                        return;                                         \
                    240:        } while (0)
                    241:
                    242: #define ADD_LINE_CPU(v, cs) \
                    243:        do {                                                            \
                    244:                if (cur >= dispstart && cur < end) {                    \
                    245:                        print_fld_size(FLD_CPU_CPU, (v));               \
1.6       mpi       246:                        print_fld_percentage(FLD_CPU_USR, (cs[CP_USER]));\
                    247:                        print_fld_percentage(FLD_CPU_NIC, (cs[CP_NICE]));\
                    248:                        print_fld_percentage(FLD_CPU_SYS, (cs[CP_SYS]));\
                    249:                        print_fld_percentage(FLD_CPU_SPIN, (cs[CP_SPIN]));\
                    250:                        print_fld_percentage(FLD_CPU_INT, (cs[CP_INTR]));\
                    251:                        print_fld_percentage(FLD_CPU_IDLE, (cs[CP_IDLE]));      \
1.1       reyk      252:                        end_line();                                     \
                    253:                }                                                       \
                    254:                if (++cur >= end)                                       \
                    255:                        return;                                         \
                    256:        } while (0)
                    257:
1.7     ! cheloha   258: #define ADD_OFFLINE_CPU(v) do {                                                \
        !           259:        if (cur >= dispstart && cur < end) {                            \
        !           260:                print_fld_size(FLD_CPU_CPU, (v));                       \
        !           261:                print_fld_str(FLD_CPU_USR, "-");                        \
        !           262:                print_fld_str(FLD_CPU_NIC, "-");                        \
        !           263:                print_fld_str(FLD_CPU_SYS, "-");                        \
        !           264:                print_fld_str(FLD_CPU_SPIN, "-");                       \
        !           265:                print_fld_str(FLD_CPU_INT, "-");                        \
        !           266:                print_fld_str(FLD_CPU_IDLE, "-");                       \
        !           267:                end_line();                                             \
        !           268:        }                                                               \
        !           269:        if (++cur >= end)                                               \
        !           270:                return;                                                 \
        !           271: } while (0)
        !           272:
1.1       reyk      273: void
                    274: print_cpu(void)
                    275: {
                    276:        int             cur = 0, c, i;
                    277:        int             end = dispstart + maxprint;
                    278:        int64_t         *states;
                    279:        double          value[CPUSTATES];
                    280:
                    281:        if (end > num_disp)
                    282:                end = num_disp;
                    283:
                    284:        for (c = 0; c < cpu_count; c++) {
1.7     ! cheloha   285:                if (!cpu_online[c]) {
        !           286:                        ADD_OFFLINE_CPU(c);
        !           287:                        continue;
        !           288:                }
1.1       reyk      289:                states = cpu_states + (CPUSTATES * c);
                    290:
                    291:                for (i = 0; i < CPUSTATES; i++)
                    292:                        value[i] = *states++;
                    293:
                    294:                ADD_LINE_CPU(c, value);
                    295:        }
                    296:
                    297:        ADD_EMPTY_LINE;
                    298: }