1 /* $OpenBSD: timer.c,v 1.1.1.1 2022/09/01 14:20:33 martijn Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Reyk Floeter <reyk@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/queue.h> 20 #include <sys/types.h> 21 #include <sys/time.h> 22 #include <sys/sched.h> 23 #include <sys/socket.h> 24 #include <sys/sysctl.h> 25 26 #include <net/if.h> 27 #include <net/if_types.h> 28 #include <netinet/in.h> 29 #include <netinet/ip.h> 30 #include <netinet/ip_var.h> 31 #include <arpa/inet.h> 32 33 #include <stdlib.h> 34 #include <stdio.h> 35 #include <errno.h> 36 #include <event.h> 37 #include <fcntl.h> 38 #include <string.h> 39 #include <unistd.h> 40 #include <pwd.h> 41 42 #include "snmpd.h" 43 #include "mib.h" 44 45 void timer_cpu(int, short, void *); 46 int percentages(int, int64_t *, int64_t *, int64_t *, int64_t *); 47 48 static int64_t **cp_time; 49 static int64_t **cp_old; 50 static int64_t **cp_diff; 51 struct event cpu_ev; 52 53 void 54 timer_cpu(int fd, short event, void *arg) 55 { 56 struct event *ev = (struct event *)arg; 57 struct timeval tv = { 60, 0 }; /* every 60 seconds */ 58 int mib[3] = { CTL_KERN, KERN_CPTIME2, 0 }, n; 59 size_t len; 60 int64_t *cptime2; 61 62 len = CPUSTATES * sizeof(int64_t); 63 for (n = 0; n < snmpd_env->sc_ncpu; n++) { 64 mib[2] = n; 65 cptime2 = snmpd_env->sc_cpustates + (CPUSTATES * n); 66 if (sysctl(mib, 3, cp_time[n], &len, NULL, 0) == -1) 67 continue; 68 (void)percentages(CPUSTATES, cptime2, cp_time[n], 69 cp_old[n], cp_diff[n]); 70 #ifdef DEBUG 71 log_debug("timer_cpu: cpu%d %lld%% idle in %llds", n, 72 (cptime2[CP_IDLE] > 1000 ? 73 1000 : (cptime2[CP_IDLE] / 10)), (long long) tv.tv_sec); 74 #endif 75 } 76 77 evtimer_add(ev, &tv); 78 } 79 80 void 81 timer_init(void) 82 { 83 int mib[] = { CTL_HW, HW_NCPU }, i; 84 size_t len; 85 86 len = sizeof(snmpd_env->sc_ncpu); 87 if (sysctl(mib, 2, &snmpd_env->sc_ncpu, &len, NULL, 0) == -1) 88 fatal("sysctl"); 89 90 snmpd_env->sc_cpustates = calloc(snmpd_env->sc_ncpu, 91 CPUSTATES * sizeof(int64_t)); 92 cp_time = calloc(snmpd_env->sc_ncpu, sizeof(int64_t *)); 93 cp_old = calloc(snmpd_env->sc_ncpu, sizeof(int64_t *)); 94 cp_diff = calloc(snmpd_env->sc_ncpu, sizeof(int64_t *)); 95 if (snmpd_env->sc_cpustates == NULL || 96 cp_time == NULL || cp_old == NULL || cp_diff == NULL) 97 fatal("calloc"); 98 for (i = 0; i < snmpd_env->sc_ncpu; i++) { 99 cp_time[i] = calloc(CPUSTATES, sizeof(int64_t)); 100 cp_old[i] = calloc(CPUSTATES, sizeof(int64_t)); 101 cp_diff[i] = calloc(CPUSTATES, sizeof(int64_t)); 102 if (cp_time[i] == NULL || cp_old[i] == NULL || 103 cp_diff[i] == NULL) 104 fatal("calloc"); 105 } 106 107 evtimer_set(&cpu_ev, timer_cpu, &cpu_ev); 108 timer_cpu(0, EV_TIMEOUT, &cpu_ev); 109 } 110 111 /* 112 * percentages() function to calculate CPU utilization. 113 * Source code derived from the top(1) utility: 114 * 115 * Copyright (c) 1984, 1989, William LeFebvre, Rice University 116 * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University 117 * 118 * Redistribution and use in source and binary forms, with or without 119 * modification, are permitted provided that the following conditions 120 * are met: 121 * 1. Redistributions of source code must retain the above copyright 122 * notice, this list of conditions and the following disclaimer. 123 * 2. Redistributions in binary form must reproduce the above copyright 124 * notice, this list of conditions and the following disclaimer in the 125 * documentation and/or other materials provided with the distribution. 126 * 127 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 128 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 129 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 130 * IN NO EVENT SHALL THE AUTHOR OR HIS EMPLOYER BE LIABLE FOR ANY DIRECT, INDIRECT, 131 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 132 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 133 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 134 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 135 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 136 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 137 */ 138 int 139 percentages(int cnt, int64_t *out, int64_t *new, int64_t *old, int64_t *diffs) 140 { 141 int64_t change, total_change, *dp, half_total; 142 int i; 143 144 /* initialization */ 145 total_change = 0; 146 dp = diffs; 147 148 /* calculate changes for each state and the overall change */ 149 for (i = 0; i < cnt; i++) { 150 if ((change = *new - *old) < 0) { 151 /* this only happens when the counter wraps */ 152 change = (*new - *old); 153 } 154 total_change += (*dp++ = change); 155 *old++ = *new++; 156 } 157 158 /* avoid divide by zero potential */ 159 if (total_change == 0) 160 total_change = 1; 161 162 /* calculate percentages based on overall change, rounding up */ 163 half_total = total_change / 2l; 164 for (i = 0; i < cnt; i++) 165 *out++ = ((*diffs++ * 1000 + half_total) / total_change); 166 167 /* return the total in case the caller wants to use it */ 168 return (total_change); 169 } 170