1181880Sjhb/*-
2181880Sjhb * Copyright (c) 2008 Yahoo!, Inc.
3181880Sjhb * All rights reserved.
4181880Sjhb * Written by: John Baldwin <jhb@FreeBSD.org>
5181880Sjhb *
6181880Sjhb * Redistribution and use in source and binary forms, with or without
7181880Sjhb * modification, are permitted provided that the following conditions
8181880Sjhb * are met:
9181880Sjhb * 1. Redistributions of source code must retain the above copyright
10181880Sjhb *    notice, this list of conditions and the following disclaimer.
11181880Sjhb * 2. Redistributions in binary form must reproduce the above copyright
12181880Sjhb *    notice, this list of conditions and the following disclaimer in the
13181880Sjhb *    documentation and/or other materials provided with the distribution.
14181880Sjhb * 3. Neither the name of the author nor the names of any co-contributors
15181880Sjhb *    may be used to endorse or promote products derived from this software
16181880Sjhb *    without specific prior written permission.
17181880Sjhb *
18181880Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19181880Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20181880Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21181880Sjhb * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22181880Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23181880Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24181880Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25181880Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26181880Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27181880Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28181880Sjhb * SUCH DAMAGE.
29181880Sjhb */
30181880Sjhb
31181880Sjhb#include <sys/cdefs.h>
32181880Sjhb__FBSDID("$FreeBSD: releng/11.0/lib/libkvm/kvm_cptime.c 291406 2015-11-27 18:58:26Z jhb $");
33181880Sjhb
34181880Sjhb#include <sys/param.h>
35181880Sjhb#include <sys/pcpu.h>
36181880Sjhb#include <sys/resource.h>
37181880Sjhb#include <sys/sysctl.h>
38181880Sjhb#include <errno.h>
39181880Sjhb#include <kvm.h>
40181880Sjhb#include <limits.h>
41181880Sjhb#include <stdlib.h>
42194186Sed#include <string.h>
43181880Sjhb
44181880Sjhb#include "kvm_private.h"
45181880Sjhb
46181880Sjhbstatic struct nlist kvm_cp_time_nl[] = {
47217744Suqs	{ .n_name = "_cp_time" },		/* (deprecated) */
48217744Suqs	{ .n_name = NULL },
49181880Sjhb};
50181880Sjhb
51181880Sjhb#define	NL_CP_TIME		0
52181880Sjhb
53181880Sjhbstatic int kvm_cp_time_cached;
54181880Sjhb
55181880Sjhbstatic int
56181880Sjhb_kvm_cp_time_init(kvm_t *kd)
57181880Sjhb{
58181880Sjhb
59181880Sjhb	if (kvm_nlist(kd, kvm_cp_time_nl) < 0)
60181880Sjhb		return (-1);
61181880Sjhb	kvm_cp_time_cached = 1;
62217744Suqs	return (0);
63181880Sjhb}
64181880Sjhb
65181880Sjhbstatic int
66181880Sjhbgetsysctl(kvm_t *kd, const char *name, void *buf, size_t len)
67181880Sjhb{
68181880Sjhb	size_t nlen;
69181880Sjhb
70181880Sjhb	nlen = len;
71181880Sjhb	if (sysctlbyname(name, buf, &nlen, NULL, 0) < 0) {
72181880Sjhb		_kvm_err(kd, kd->program, "cannot read sysctl %s:%s", name,
73181880Sjhb		    strerror(errno));
74181880Sjhb		return (-1);
75181880Sjhb	}
76181880Sjhb	if (nlen != len) {
77181880Sjhb		_kvm_err(kd, kd->program, "sysctl %s has unexpected size",
78181880Sjhb		    name);
79181880Sjhb		return (-1);
80181880Sjhb	}
81181880Sjhb	return (0);
82181880Sjhb}
83181880Sjhb
84181880Sjhbint
85181880Sjhbkvm_getcptime(kvm_t *kd, long *cp_time)
86181880Sjhb{
87181880Sjhb	struct pcpu *pc;
88181880Sjhb	int i, j, maxcpu;
89181880Sjhb
90181880Sjhb	if (kd == NULL) {
91181880Sjhb		kvm_cp_time_cached = 0;
92181880Sjhb		return (0);
93181880Sjhb	}
94181880Sjhb
95181880Sjhb	if (ISALIVE(kd))
96181880Sjhb		return (getsysctl(kd, "kern.cp_time", cp_time, sizeof(long) *
97181880Sjhb		    CPUSTATES));
98181880Sjhb
99291406Sjhb	if (!kd->arch->ka_native(kd)) {
100291406Sjhb		_kvm_err(kd, kd->program,
101291406Sjhb		    "cannot read cp_time from non-native core");
102291406Sjhb		return (-1);
103291406Sjhb	}
104291406Sjhb
105181880Sjhb	if (kvm_cp_time_cached == 0) {
106181880Sjhb		if (_kvm_cp_time_init(kd) < 0)
107181880Sjhb			return (-1);
108181880Sjhb	}
109181880Sjhb
110181880Sjhb	/* If this kernel has a "cp_time[]" symbol, then just read that. */
111181880Sjhb	if (kvm_cp_time_nl[NL_CP_TIME].n_value != 0) {
112181880Sjhb		if (kvm_read(kd, kvm_cp_time_nl[NL_CP_TIME].n_value, cp_time,
113181880Sjhb		    sizeof(long) * CPUSTATES) != sizeof(long) * CPUSTATES) {
114181880Sjhb			_kvm_err(kd, kd->program, "cannot read cp_time array");
115181880Sjhb			return (-1);
116181880Sjhb		}
117181880Sjhb		return (0);
118181880Sjhb	}
119181880Sjhb
120181880Sjhb	/*
121181880Sjhb	 * If we don't have that symbol, then we have to simulate
122181880Sjhb	 * "cp_time[]" by adding up the individual times for each CPU.
123181880Sjhb	 */
124181880Sjhb	maxcpu = kvm_getmaxcpu(kd);
125181880Sjhb	if (maxcpu < 0)
126181880Sjhb		return (-1);
127181880Sjhb	for (i = 0; i < CPUSTATES; i++)
128181880Sjhb		cp_time[i] = 0;
129181880Sjhb	for (i = 0; i < maxcpu; i++) {
130181880Sjhb		pc = kvm_getpcpu(kd, i);
131181880Sjhb		if (pc == NULL)
132181880Sjhb			continue;
133181880Sjhb		if (pc == (void *)-1)
134181880Sjhb			return (-1);
135181880Sjhb		for (j = 0; j < CPUSTATES; j++)
136181880Sjhb			cp_time[j] += pc->pc_cp_time[j];
137181880Sjhb		free(pc);
138181880Sjhb	}
139181880Sjhb	return (0);
140181880Sjhb}
141