GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/systat/cpu.c Lines: 0 57 0.0 %
Date: 2016-12-06 Branches: 0 48 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: cpu.c,v 1.5 2016/01/02 20:02:40 benno Exp $	*/
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/signal.h>
50
#include <sys/sched.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, NULL
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
	int		cur = 0, c, i;
250
	int		end = dispstart + maxprint;
251
	int64_t		*states;
252
	double		value[CPUSTATES];
253
254
	if (end > num_disp)
255
		end = num_disp;
256
257
	for (c = 0; c < cpu_count; c++) {
258
		states = cpu_states + (CPUSTATES * c);
259
260
		for (i = 0; i < CPUSTATES; i++)
261
			value[i] = *states++;
262
263
		ADD_LINE_CPU(c, value);
264
	}
265
266
	ADD_EMPTY_LINE;
267
}