kvm_cptime.c revision 194186
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: head/lib/libkvm/kvm_cptime.c 194186 2009-06-14 12:42:06Z ed $");
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[] = {
47181880Sjhb	{ "_cp_time" },			/* (deprecated) */
48181880Sjhb	{ 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;
62181880Sjhb}
63181880Sjhb
64181880Sjhbstatic int
65181880Sjhbgetsysctl(kvm_t *kd, const char *name, void *buf, size_t len)
66181880Sjhb{
67181880Sjhb	size_t nlen;
68181880Sjhb
69181880Sjhb	nlen = len;
70181880Sjhb	if (sysctlbyname(name, buf, &nlen, NULL, 0) < 0) {
71181880Sjhb		_kvm_err(kd, kd->program, "cannot read sysctl %s:%s", name,
72181880Sjhb		    strerror(errno));
73181880Sjhb		return (-1);
74181880Sjhb	}
75181880Sjhb	if (nlen != len) {
76181880Sjhb		_kvm_err(kd, kd->program, "sysctl %s has unexpected size",
77181880Sjhb		    name);
78181880Sjhb		return (-1);
79181880Sjhb	}
80181880Sjhb	return (0);
81181880Sjhb}
82181880Sjhb
83181880Sjhbint
84181880Sjhbkvm_getcptime(kvm_t *kd, long *cp_time)
85181880Sjhb{
86181880Sjhb	struct pcpu *pc;
87181880Sjhb	int i, j, maxcpu;
88181880Sjhb
89181880Sjhb	if (kd == NULL) {
90181880Sjhb		kvm_cp_time_cached = 0;
91181880Sjhb		return (0);
92181880Sjhb	}
93181880Sjhb
94181880Sjhb	if (ISALIVE(kd))
95181880Sjhb		return (getsysctl(kd, "kern.cp_time", cp_time, sizeof(long) *
96181880Sjhb		    CPUSTATES));
97181880Sjhb
98181880Sjhb	if (kvm_cp_time_cached == 0) {
99181880Sjhb		if (_kvm_cp_time_init(kd) < 0)
100181880Sjhb			return (-1);
101181880Sjhb	}
102181880Sjhb
103181880Sjhb	/* If this kernel has a "cp_time[]" symbol, then just read that. */
104181880Sjhb	if (kvm_cp_time_nl[NL_CP_TIME].n_value != 0) {
105181880Sjhb		if (kvm_read(kd, kvm_cp_time_nl[NL_CP_TIME].n_value, cp_time,
106181880Sjhb		    sizeof(long) * CPUSTATES) != sizeof(long) * CPUSTATES) {
107181880Sjhb			_kvm_err(kd, kd->program, "cannot read cp_time array");
108181880Sjhb			return (-1);
109181880Sjhb		}
110181880Sjhb		return (0);
111181880Sjhb	}
112181880Sjhb
113181880Sjhb	/*
114181880Sjhb	 * If we don't have that symbol, then we have to simulate
115181880Sjhb	 * "cp_time[]" by adding up the individual times for each CPU.
116181880Sjhb	 */
117181880Sjhb	maxcpu = kvm_getmaxcpu(kd);
118181880Sjhb	if (maxcpu < 0)
119181880Sjhb		return (-1);
120181880Sjhb	for (i = 0; i < CPUSTATES; i++)
121181880Sjhb		cp_time[i] = 0;
122181880Sjhb	for (i = 0; i < maxcpu; i++) {
123181880Sjhb		pc = kvm_getpcpu(kd, i);
124181880Sjhb		if (pc == NULL)
125181880Sjhb			continue;
126181880Sjhb		if (pc == (void *)-1)
127181880Sjhb			return (-1);
128181880Sjhb		for (j = 0; j < CPUSTATES; j++)
129181880Sjhb			cp_time[j] += pc->pc_cp_time[j];
130181880Sjhb		free(pc);
131181880Sjhb	}
132181880Sjhb	return (0);
133181880Sjhb}
134