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