diff options
Diffstat (limited to 'src/pmdas/netbsd')
-rw-r--r-- | src/pmdas/netbsd/GNUmakefile | 68 | ||||
-rw-r--r-- | src/pmdas/netbsd/disk.c | 216 | ||||
-rw-r--r-- | src/pmdas/netbsd/help | 95 | ||||
-rw-r--r-- | src/pmdas/netbsd/netbsd.c | 981 | ||||
-rw-r--r-- | src/pmdas/netbsd/netbsd.h | 44 | ||||
-rw-r--r-- | src/pmdas/netbsd/netif.c | 233 | ||||
-rw-r--r-- | src/pmdas/netbsd/root_netbsd | 172 |
7 files changed, 1809 insertions, 0 deletions
diff --git a/src/pmdas/netbsd/GNUmakefile b/src/pmdas/netbsd/GNUmakefile new file mode 100644 index 0000000..c904009 --- /dev/null +++ b/src/pmdas/netbsd/GNUmakefile @@ -0,0 +1,68 @@ +# +# Copyright (c) 2000,2003,2004,2008 Silicon Graphics, Inc. All Rights Reserved. +# Copyright (c) 2007-2010 Aconex. All Rights Reserved. +# Copyright (c) 2012 Ken McDonell. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# + +TOPDIR = ../../.. +include $(TOPDIR)/src/include/builddefs + +IAM = netbsd +DOMAIN = NETBSD +CMDTARGET = pmdanetbsd +LIBTARGET = pmda_netbsd.so +PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) +CONF_LINE = "netbsd 116 dso netbsd_init $(PMDADIR)/$(LIBTARGET)" + +CFILES = netbsd.c disk.c netif.c + +HFILES = netbsd.h + +LSRCFILES = help root_netbsd +LDIRT = help.dir help.pag help.sed help.tmp domain.h $(IAM).log + +LLDLIBS = $(PCP_PMDALIB) -lkvm + +default: build-me + +include $(BUILDRULES) + +ifeq "$(TARGET_OS)" "netbsd" +build-me: domain.h $(LIBTARGET) $(CMDTARGET) help.dir help.pag + @if [ `grep -c $(CONF_LINE) ../pmcd.conf` -eq 0 ]; then \ + echo $(CONF_LINE) >> ../pmcd.conf ; \ + fi + +install: default + $(INSTALL) -m 755 -d $(PMDADIR) + $(INSTALL) -m 644 domain.h help help.dir help.pag $(PMDADIR) + $(INSTALL) -m 755 $(LIBTARGET) $(CMDTARGET) $(PMDADIR) + $(INSTALL) -m 644 root_netbsd $(PCP_VAR_DIR)/pmns/root_netbsd +else +build-me: +install: +endif + +help.dir help.pag : domain.h help + $(SED) <domain.h >help.sed -n -e '/#define/s/#define[ ]*\([A-Z][A-Z]*\)[ ]*\([0-9][0-9]*\)/s@\1@\2@/p' + $(SED) -f help.sed <help >help.tmp + $(RUN_IN_BUILD_ENV) $(TOPDIR)/src/newhelp/newhelp -n root_netbsd -v 2 -o help <help.tmp + +default_pcp : default + +install_pcp : install + +domain.h: ../../pmns/stdpmid + $(DOMAIN_MAKERULE) + +$(OBJECTS): domain.h netbsd.h diff --git a/src/pmdas/netbsd/disk.c b/src/pmdas/netbsd/disk.c new file mode 100644 index 0000000..b188ae4 --- /dev/null +++ b/src/pmdas/netbsd/disk.c @@ -0,0 +1,216 @@ +/* + * NetBSD Kernel PMDA - disk metrics + * + * Copyright (c) 2012,2013 Ken McDonell. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "pmapi.h" +#include "impl.h" +#include "pmda.h" +#include "netbsd.h" + +#if 0 +#include <devstat.h> +struct devinfo devinfo = { 0 }; +struct statinfo statinfo; +#endif + +void +refresh_disk_metrics(void) +{ +#if 0 + static int init_done = 0; + int i; + int sts; + + if (!init_done) { + sts = devstat_checkversion(NULL); + if (sts != 0) { + fprintf(stderr, "refresh_disk_metrics: devstat_checkversion: failed! %s\n", devstat_errbuf); + exit(1); + } + statinfo.dinfo = &devinfo; + init_done = 1; + } + + sts = devstat_getdevs(NULL, &statinfo); + if (sts < 0) { + fprintf(stderr, "refresh_disk_metrics: devstat_getdevs: %s\n", strerror(errno)); + exit(1); + } + else if (sts == 1) { + /* + * First call, else devstat[] list has changed + */ + struct devstat *dsp; + char iname[DEVSTAT_NAME_LEN+6]; + pmdaCacheOp(indomtab[DISK_INDOM].it_indom, PMDA_CACHE_INACTIVE); + for (i = 0; i < devinfo.numdevs; i++) { + dsp = &devinfo.devices[i]; + /* + * Skip entries that are not interesting ... only include + * "da" (direct access) disks at this stage + */ + if (strcmp(dsp->device_name, "da") != 0) + continue; + snprintf(iname, sizeof(iname), "%s%d", dsp->device_name, dsp->unit_number); + sts = pmdaCacheLookupName(indomtab[DISK_INDOM].it_indom, iname, NULL, NULL); + if (sts == PMDA_CACHE_ACTIVE) { + int j; + fprintf(stderr, "refresh_disk_metrics: Warning: duplicate name (%s) in disk indom\n", iname); + for (j = 0; j < devinfo.numdevs; j++) { + dsp = &devinfo.devices[j]; + fprintf(stderr, " devinfo[%d]: %s%d\n", j, dsp->device_name, dsp->unit_number); + } + continue; + } + else { + /* new entry or reactivate an existing one */ + pmdaCacheStore(indomtab[DISK_INDOM].it_indom, PMDA_CACHE_ADD, iname, (void *)dsp); + } + } + } +#endif + +} + +int +do_disk_metrics(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) +{ +#if 0 + struct devstat *dsp; + int sts; + + if (inst != PM_IN_NULL) { + /* + * per-disk metrics + */ + sts = pmdaCacheLookup(indomtab[DISK_INDOM].it_indom, inst, NULL, (void **)&dsp); + if (sts == PMDA_CACHE_ACTIVE) { + sts = 1; + /* cluster and domain already checked, just need item ... */ + switch (pmid_item(mdesc->m_desc.pmid)) { + case 0: /* disk.dev.read */ + atom->ull = dsp->operations[DEVSTAT_READ]; + break; + + case 1: /* disk.dev.write */ + atom->ull = dsp->operations[DEVSTAT_WRITE]; + break; + + case 2: /* disk.dev.total */ + atom->ull = dsp->operations[DEVSTAT_READ] + dsp->operations[DEVSTAT_WRITE]; + break; + + case 3: /* disk.dev.read_bytes */ + atom->ull = dsp->bytes[DEVSTAT_READ]; + break; + + case 4: /* disk.dev.write_bytes */ + atom->ull = dsp->bytes[DEVSTAT_WRITE]; + break; + + case 5: /* disk.dev.total_bytes */ + atom->ull = dsp->bytes[DEVSTAT_READ] + dsp->bytes[DEVSTAT_WRITE]; + break; + + case 12: /* disk.dev.blkread */ + atom->ull = dsp->block_size == 0 ? 0 : dsp->bytes[DEVSTAT_READ] / dsp->block_size; + break; + + case 13: /* disk.dev.blkwrite */ + atom->ull = dsp->block_size == 0 ? 0 : dsp->bytes[DEVSTAT_WRITE] / dsp->block_size; + break; + + case 14: /* disk.dev.blktotal */ + atom->ull = dsp->block_size == 0 ? 0 : (dsp->bytes[DEVSTAT_READ] + dsp->bytes[DEVSTAT_WRITE]) / dsp->block_size; + break; + + default: + sts = PM_ERR_PMID; + break; + } + } + else + sts = 0; + } + else { + /* + * all-disk summary metrics + */ + int i; + atom->ull = 0; + sts = 1; + pmdaCacheOp(indomtab[DISK_INDOM].it_indom, PMDA_CACHE_WALK_REWIND); + while (sts == 1 && (i = pmdaCacheOp(indomtab[DISK_INDOM].it_indom, PMDA_CACHE_WALK_NEXT)) >= 0) { + int lsts; + lsts = pmdaCacheLookup(indomtab[DISK_INDOM].it_indom, i, NULL, (void **)&dsp); + if (lsts == PMDA_CACHE_ACTIVE) { + /* cluster and domain already checked, just need item ... */ + switch (pmid_item(mdesc->m_desc.pmid)) { + case 6: /* disk.all.read */ + atom->ull += dsp->operations[DEVSTAT_READ]; + break; + + case 7: /* disk.all.write */ + atom->ull += dsp->operations[DEVSTAT_WRITE]; + break; + + case 8: /* disk.all.total */ + atom->ull += dsp->operations[DEVSTAT_READ] + dsp->operations[DEVSTAT_WRITE]; + break; + + case 9: /* disk.all.read_bytes */ + atom->ull += dsp->bytes[DEVSTAT_READ]; + break; + + case 10: /* disk.all.write_bytes */ + atom->ull += dsp->bytes[DEVSTAT_WRITE]; + break; + + case 11: /* disk.all.total_bytes */ + atom->ull += dsp->bytes[DEVSTAT_READ] + dsp->bytes[DEVSTAT_WRITE]; + break; + + case 15: /* disk.all.blkread */ + atom->ull += dsp->block_size == 0 ? 0 : dsp->bytes[DEVSTAT_READ] / dsp->block_size; + break; + + case 16: /* disk.all.blkwrite */ + atom->ull += dsp->block_size == 0 ? 0 : dsp->bytes[DEVSTAT_WRITE] / dsp->block_size; + break; + + case 17: /* disk.all.blktotal */ + atom->ull += dsp->block_size == 0 ? 0 : (dsp->bytes[DEVSTAT_READ] + dsp->bytes[DEVSTAT_WRITE]) / dsp->block_size; + break; + + default: + sts = PM_ERR_PMID; + break; + } + } + } + if (i < 0 && i != -1) + /* not end of indom from cache walk, some other error */ + sts = i; + } + + return sts; +#else + return PM_ERR_PMID; +#endif +} diff --git a/src/pmdas/netbsd/help b/src/pmdas/netbsd/help new file mode 100644 index 0000000..50cf1ea --- /dev/null +++ b/src/pmdas/netbsd/help @@ -0,0 +1,95 @@ +@ NETBSD.0 Instance domain for load average +Universally 3 instances, "1 minute" (1), "5 minute" (5) and +"15 minute" (15). + +@ NETBSD.1 CPU Instance domain for kernel.percpu metrics +One instance for each physical CPU. + +@ NETBSD.2 DISK Instance domain for disk.dev metrics +One instance for each physical "direct access" device. + +@ kernel.all.hz system hz rate +Microseconds per "hz" tick. +@ kernel.all.load 1, 5 and 15 minute load average +@ kernel.all.pswitch count of context switches +@ kernel.all.syscall count of system calls +@ kernel.all.intr count of interrupts serviced +@ kernel.all.cpu.user total user CPU time for all CPUs +@ kernel.all.cpu.nice total nice user CPU time for all CPUs +@ kernel.all.cpu.sys total sys CPU time for all CPUs +@ kernel.all.cpu.intr total interrupt CPU time for all CPUs +@ kernel.all.cpu.idle total idle CPU time for all CPUs +@ kernel.percpu.cpu.user user CPU time for each CPU +@ kernel.percpu.cpu.nice nice user CPU time for each CPU +@ kernel.percpu.cpu.sys sys CPU time for each CPU +@ kernel.percpu.cpu.intr interrupt CPU time for each CPU +@ kernel.percpu.cpu.idle idle CPU time for each CPU + +@ hinv.ncpu number of CPUs in the system +@ hinv.ndisk number of disks in the system +@ hinv.physmem total system memory +@ hinv.pagesize kernel page size +@ hinv.cpu.vendor system's CPU vendor +@ hinv.cpu.model system's CPU model +@ hinv.cpu.arch system's machine dependent CPU architecture type + +@ swap.length total swap space size +@ swap.used reserved (or allocated) swap space +@ swap.free available swap space + +@ swap.pagesin pages read from external storage to service page faults +@ swap.pagesout dirty pages written to swap devices +When the rate of page writes is non-zero, this is the most useful +indication severe demand for physical memory. +@ swap.in number of swap in operations +@ swap.out number of swap out operations + +@ disk.dev.read Count of read operations per disk +@ disk.dev.write Count of write operations per disk +@ disk.dev.total Count of read or write operations (IOPs) per disk +@ disk.dev.read_bytes Count of bytes read from each disk +@ disk.dev.write_bytes Count of bytes written to each disk +@ disk.dev.total_bytes Count of bytes transferred to or from each disk +@ disk.dev.blkread Count of blocks read from each disk +@ disk.dev.blkwrite Count of blocks written to each disk +@ disk.dev.blktotal Count of blocks transferred to or from each disk +@ disk.all.read Count of read operations across all disks +@ disk.all.write Count of write operations across all disks +@ disk.all.total Count of read or write operations (IOPs) across all disks +@ disk.all.read_bytes Count of bytes read from all disks +@ disk.all.write_bytes Count of bytes written to all disks +@ disk.all.total_bytes Count of bytes transferred to or from all disks +@ disk.all.blkread Count of blocks read from all disks +@ disk.all.blkwrite Count of blocks written to all disks +@ disk.all.blktotal Count of blocks transferred to or from all disks + +@ mem.util.all Total memory managed by the system +@ mem.util.used Memory that is actively in use +Equals "all" minus "free" minus "inactive" minus "cached". +@ mem.util.free Unallocated and free memory +@ mem.util.bufmem Memory associated with active buffer I/O +@ mem.util.cached Cached memory +Unmodified (clean and cached) pages from files in filesystems. +@ mem.util.wired Wired or pinned memory that cannot be paged out +@ mem.util.active Recently accessed memory +@ mem.util.inactive Memory that is in use, but has not be accessed recently +@ mem.util.avail Available memory +Free plus inactive plus cached. + +@ network.interface.mtu Maximum Transfer Unit for each network interface +@ network.interface.up "UP" state for each network interface +@ network.interface.baudrate Data baudrate for each network interface +@ network.interface.in.bytes Bytes received on each network interface +@ network.interface.in.packets Packets received on each network interface +@ network.interface.in.mcasts Multicast packets received on each network interface +@ network.interface.in.errors Input errors on each network interface +@ network.interface.in.drops Dropped packets on each network interface +@ network.interface.out.bytes Bytes transmitted on each network interface +@ network.interface.out.packets Packets transmitted on each network interface +@ network.interface.out.mcasts Multicast packets transmitted on each network interface +@ network.interface.out.errors Output errors on each network interface +@ network.interface.out.collisions Output collisions on each network interface +@ network.interface.total.bytes Bytes received or transmitted on each network interface +@ network.interface.total.packets Packets received or transmitted on each network interface +@ network.interface.total.mcasts Multicast packets received or transmitted on each network interface +@ network.interface.total.errors Input or output errors on each network interface diff --git a/src/pmdas/netbsd/netbsd.c b/src/pmdas/netbsd/netbsd.c new file mode 100644 index 0000000..d0c68bc --- /dev/null +++ b/src/pmdas/netbsd/netbsd.c @@ -0,0 +1,981 @@ +/* + * NetBSD Kernel PMDA + * + * Copyright (c) 2012 Red Hat. + * Copyright (c) 2012,2013 Ken McDonell. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "pmapi.h" +#include "impl.h" +#include "pmda.h" + +#include <limits.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/sysctl.h> +#include <sys/resource.h> +#include <sys/time.h> +#include <uvm/uvm_param.h> + +#include "domain.h" +#include "netbsd.h" + +/* static instances */ +static pmdaInstid loadav_indom[] = { + { 1, "1 minute" }, { 5, "5 minute" }, { 15, "15 minute" } +}; + +/* instance domains */ +pmdaIndom indomtab[] = { + { LOADAV_INDOM, sizeof(loadav_indom)/sizeof(loadav_indom[0]), loadav_indom }, + { CPU_INDOM, 0, NULL }, + { DISK_INDOM, 0, NULL }, + { NETIF_INDOM, 0, NULL }, +}; +static int indomtablen = sizeof(indomtab) / sizeof(indomtab[0]); + +#define CL_SYSCTL 0 +#define CL_SPECIAL 1 +#define CL_DISK 2 +#define CL_NETIF 3 + +/* + * All the PCP metrics. + * + * For sysctl metrics, m_user (the first field) is set the the PCP + * name of the metric, and during initialization this is replaced by + * a pointer to the corresponding entry in mib[] (based on matching, + * or prefix matching (see matchname()) the PCP name here with + * m_pcpname[] in the mib[] entries. + * + * cluster map + * CL_SYSCTL simple sysctl() metrics, either one metric per mib, or + * one struct per mib + * CL_SPECIAL trickier sysctl() metrics involving synthesis or arithmetic + * or other methods + * CL_DISK disk metrics + * CL_NETIF network interface metrics + */ + +static pmdaMetric metrictab[] = { + { (void *)"hinv.ncpu", + { PMDA_PMID(CL_SYSCTL,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, + PMDA_PMUNITS(0,0,0,0,0,0) } }, + { (void *)"hinv.physmem", + { PMDA_PMID(CL_SYSCTL,1), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_DISCRETE, + PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, + { (void *)"kernel.all.load", + { PMDA_PMID(CL_SYSCTL,2), PM_TYPE_FLOAT, LOADAV_INDOM, PM_SEM_INSTANT, + PMDA_PMUNITS(0,0,0,0,0,0) } }, + { (void *)"kernel.all.cpu.user", + { PMDA_PMID(CL_SYSCTL,3), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, + PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, + { (void *)"kernel.all.cpu.nice", + { PMDA_PMID(CL_SYSCTL,4), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, + PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, + { (void *)"kernel.all.cpu.sys", + { PMDA_PMID(CL_SYSCTL,5), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, + PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, + { (void *)"kernel.all.cpu.intr", + { PMDA_PMID(CL_SYSCTL,6), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, + PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, + { (void *)"kernel.all.cpu.idle", + { PMDA_PMID(CL_SYSCTL,7), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, + PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, + { (void *)"kernel.percpu.cpu.user", + { PMDA_PMID(CL_SYSCTL,8), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, + { (void *)"kernel.percpu.cpu.nice", + { PMDA_PMID(CL_SYSCTL,9), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, + { (void *)"kernel.percpu.cpu.sys", + { PMDA_PMID(CL_SYSCTL,10), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, + { (void *)"kernel.percpu.cpu.intr", + { PMDA_PMID(CL_SYSCTL,11), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, + { (void *)"kernel.percpu.cpu.idle", + { PMDA_PMID(CL_SYSCTL,12), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, + { (void *)"kernel.all.hz", + { PMDA_PMID(CL_SYSCTL,13), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, + PMDA_PMUNITS(0,1,0,0,PM_TIME_USEC,0) } }, + { (void *)"hinv.cpu.vendor", + { PMDA_PMID(CL_SYSCTL,15), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, + PMDA_PMUNITS(0,0,0,0,0,0) } }, + { (void *)"hinv.cpu.model", + { PMDA_PMID(CL_SYSCTL,16), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, + PMDA_PMUNITS(0,0,0,0,0,0) } }, + { (void *)"hinv.cpu.arch", + { PMDA_PMID(CL_SYSCTL,17), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, + PMDA_PMUNITS(0,0,0,0,0,0) } }, + { (void *)"swap.pagesin", + { PMDA_PMID(CL_SYSCTL,18), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, + { (void *)"swap.pagesout", + { PMDA_PMID(CL_SYSCTL,19), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, + { (void *)"swap.in", + { PMDA_PMID(CL_SYSCTL,20), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, + { (void *)"swap.in", + { PMDA_PMID(CL_SYSCTL,21), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, + { (void *)"kernel.all.pswitch", + { PMDA_PMID(CL_SYSCTL,22), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, + { (void *)"kernel.all.syscall", + { PMDA_PMID(CL_SYSCTL,23), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, + { (void *)"kernel.all.intr", + { PMDA_PMID(CL_SYSCTL,24), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, + { (void *)"swap.length", + { PMDA_PMID(CL_SYSCTL,25), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, + PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, + { (void *)"swap.used", + { PMDA_PMID(CL_SYSCTL,26), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, + PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, + + { NULL, /* hinv.ndisk */ + { PMDA_PMID(CL_SPECIAL,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, + PMDA_PMUNITS(0,0,0,0,0,0) } }, + /* + * swap.free is the difference between sysctl variables vm.swap_total + * and vm.swap_reserved, so it is important they are kept together + * in mib[] below + */ + { (void *)"swap.length", /* swap.free */ + { PMDA_PMID(CL_SPECIAL,1), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, + PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, + { NULL, /* hinv.pagesize */ + { PMDA_PMID(CL_SPECIAL,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, + PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, + { (void *)"mem.util.all", + { PMDA_PMID(CL_SPECIAL,4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, + PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, + /* + * mem.util.used is computed from several of the vm.stats.vm.v_*_count + * sysctl metrics, so it is important they are kept together in mib[] + * below + */ + { (void *)"mem.util.all", /* mem.util.used */ + { PMDA_PMID(CL_SPECIAL,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, + PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, + { (void *)"mem.util.free", + { PMDA_PMID(CL_SPECIAL,6), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, + PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, + { (void *)"mem.util.bufmem", + { PMDA_PMID(CL_SPECIAL,7), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, + PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, + { (void *)"mem.util.cached", + { PMDA_PMID(CL_SPECIAL,8), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, + PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, + { (void *)"mem.util.wired", + { PMDA_PMID(CL_SPECIAL,9), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, + PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, + { (void *)"mem.util.active", + { PMDA_PMID(CL_SPECIAL,10), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, + PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, + { (void *)"mem.util.inactive", + { PMDA_PMID(CL_SPECIAL,11), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, + PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, + /* + * mem.util.avail is computed from several of the vm.stats.vm.v_*_count + * sysctl metrics, so it is important they are kept together in mib[] + * below + */ + { (void *)"mem.util.all", /* mem.util.avail */ + { PMDA_PMID(CL_SPECIAL,12), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, + PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, + + { NULL, /* disk.dev.read */ + { PMDA_PMID(CL_DISK,0), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, + { NULL, /* disk.dev.write */ + { PMDA_PMID(CL_DISK,1), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, + { NULL, /* disk.dev.total */ + { PMDA_PMID(CL_DISK,2), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, + { NULL, /* disk.dev.read_bytes */ + { PMDA_PMID(CL_DISK,3), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, + { NULL, /* disk.dev.write_bytes */ + { PMDA_PMID(CL_DISK,4), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, + { NULL, /* disk.dev.total_bytes */ + { PMDA_PMID(CL_DISK,5), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, + { NULL, /* disk.all.read */ + { PMDA_PMID(CL_DISK,6), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, + { NULL, /* disk.all.write */ + { PMDA_PMID(CL_DISK,7), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, + { NULL, /* disk.all.total */ + { PMDA_PMID(CL_DISK,8), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, + { NULL, /* disk.all.read_bytes */ + { PMDA_PMID(CL_DISK,9), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, + PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, + { NULL, /* disk.all.write_bytes */ + { PMDA_PMID(CL_DISK,10), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, + PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, + { NULL, /* disk.all.total_bytes */ + { PMDA_PMID(CL_DISK,11), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, + PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, + { NULL, /* disk.dev.blkread */ + { PMDA_PMID(CL_DISK,12), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, + { NULL, /* disk.dev.blkwrite */ + { PMDA_PMID(CL_DISK,13), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, + { NULL, /* disk.dev.blktotal */ + { PMDA_PMID(CL_DISK,14), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, + { NULL, /* disk.all.blkread */ + { PMDA_PMID(CL_DISK,15), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, + { NULL, /* disk.all.blkwrite */ + { PMDA_PMID(CL_DISK,16), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, + { NULL, /* disk.all.blktotal */ + { PMDA_PMID(CL_DISK,17), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, + + { NULL, /* network.interface.mtu */ + { PMDA_PMID(CL_NETIF,0), PM_TYPE_U32, NETIF_INDOM, PM_SEM_INSTANT, + PMDA_PMUNITS(0,0,0,0,0,0) } }, + { NULL, /* network.interface.up */ + { PMDA_PMID(CL_NETIF,1), PM_TYPE_U32, NETIF_INDOM, PM_SEM_INSTANT, + PMDA_PMUNITS(0,0,0,0,0,0) } }, + { NULL, /* network.interface.baudrate */ + { PMDA_PMID(CL_NETIF,2), PM_TYPE_U64, NETIF_INDOM, PM_SEM_INSTANT, + PMDA_PMUNITS(0,0,0,0,0,0) } }, + { NULL, /* network.interface.in.bytes */ + { PMDA_PMID(CL_NETIF,3), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, + { NULL, /* network.interface.in.packets */ + { PMDA_PMID(CL_NETIF,4), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, + { NULL, /* network.interface.in.mcasts */ + { PMDA_PMID(CL_NETIF,5), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, + { NULL, /* network.interface.in.errors */ + { PMDA_PMID(CL_NETIF,6), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, + { NULL, /* network.interface.in.drops */ + { PMDA_PMID(CL_NETIF,7), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, + { NULL, /* network.interface.out.bytes */ + { PMDA_PMID(CL_NETIF,8), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, + { NULL, /* network.interface.out.packets */ + { PMDA_PMID(CL_NETIF,9), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, + { NULL, /* network.interface.out.mcasts */ + { PMDA_PMID(CL_NETIF,10), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, + { NULL, /* network.interface.out.errors */ + { PMDA_PMID(CL_NETIF,11), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, + { NULL, /* network.interface.out.collisions */ + { PMDA_PMID(CL_NETIF,12), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, + { NULL, /* network.interface.total.bytes */ + { PMDA_PMID(CL_NETIF,13), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, + { NULL, /* network.interface.total.packets */ + { PMDA_PMID(CL_NETIF,14), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, + { NULL, /* network.interface.total.mcasts */ + { PMDA_PMID(CL_NETIF,15), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, + { NULL, /* network.interface.total.errors */ + { PMDA_PMID(CL_NETIF,16), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, +}; +static int metrictablen = sizeof(metrictab) / sizeof(metrictab[0]); + +/* + * mapping between PCP metrics and sysctl metrics + * + * initialization note ... all elments after m_pcpname and m_name are OK + * to be 0 or NULL + */ +typedef struct { + const char *m_pcpname; /* PCP metric name or prefix (see matchname() */ + const char *m_name; /* sysctl metric name */ + size_t m_miblen; /* number of elements in m_mib[] */ + int *m_mib; + int m_fetched; /* 1 if m_data is current and valid */ + size_t m_datalen; /* number of bytes in m_data[] */ + void *m_data; /* value from sysctl */ +} mib_t; +static mib_t map[] = { + { "hinv.ncpu", "hw.ncpu" }, + { "hinv.physmem", "hw.physmem" }, + { "hinv.cpu.vendor", "hw.machine" }, + { "hinv.cpu.model", "hw.model" }, + { "hinv.cpu.arch", "hw.machine_arch" }, + { "kernel.all.load", "vm.loadavg" }, + { "kernel.all.hz", "kern.clockrate" }, + { "kernel.all.cpu.*", "kern.cp_time" }, + // need special logic for kern.cp_time.0 ? { "kernel.percpu.cpu.*", "kern.cp_times." }, + // not here? { "swap.pagesin", "vm.stats.vm.v_swappgsin" }, + // not here? { "swap.pagesout", "vm.stats.vm.v_swappgsout" }, + // not here? { "swap.in", "vm.stats.vm.v_swapin" }, + { "swap.out", "vm.swapout" }, + // not here? { "kernel.all.pswitch", "vm.stats.sys.v_swtch" }, + // not here? { "kernel.all.syscall", "vm.stats.sys.v_syscall" }, + // not here? { "kernel.all.intr", "vm.stats.sys.v_intr" }, + { "mem.util.bufmem", "vfs.bufspace" }, +/* + * DO NOT MOVE next 2 entries ... see note above for swap.free + */ + // not here? { "swap.length", "vm.swap_total" }, + // not here? { "swap.used", "vm.swap_reserved" }, +/* + * DO NOT MOVE next 6 entries ... see note above for mem.util.avail + * and mem.util.used + */ + // not here? { "mem.util.all", "vm.stats.vm.v_page_count" }, + // not here? { "mem.util.free", "vm.stats.vm.v_free_count" }, + // not here? { "mem.util.cached", "vm.stats.vm.v_cache_count" }, + // not here? { "mem.util.wired", "vm.stats.vm.v_wire_count" }, + // not here? { "mem.util.active", "vm.stats.vm.v_active_count" }, + // not here? { "mem.util.inactive", "vm.stats.vm.v_inactive_count" }, + +}; +static int maplen = sizeof(map) / sizeof(map[0]); +static mib_t bad_mib = { "bad.mib", "bad.mib", 0, NULL, 0, 0, NULL }; + +static char *username; +static int isDSO = 1; /* =0 I am a daemon */ +static int cpuhz; /* frequency for CPU time metrics */ +static int ncpu; /* number of cpus in kern.cp_times.* data */ +static int pagesize; /* vm page size */ + +/* + * Fetch values from sysctl() + * + * Expect the result to be xpect bytes to match the PCP data size or + * anticipated structure size, unless xpect is ==0 in which case the + * size test is skipped. + */ +static int +do_sysctl(mib_t *mp, size_t xpect) +{ + /* + * Note zero trip if mp->m_data and mp->datalen are already valid + * and current + */ + for ( ; mp->m_fetched == 0; ) { + int sts; + sts = sysctl(mp->m_mib, (u_int)mp->m_miblen, mp->m_data, &mp->m_datalen, NULL, 0); + fprintf(stderr, "sysctl(%s%s) -> %d (datalen=%d)\n", mp->m_name, mp->m_data == NULL ? " firstcall" : "", sts, (int)mp->m_datalen); + if (sts == 0 && mp->m_data != NULL) { + mp->m_fetched = 1; + break; + } + if ((sts == -1 && errno == ENOMEM) || (sts == 0 && mp->m_data == NULL)) { + /* first call for this one, or data changed size */ + mp->m_data = realloc(mp->m_data, mp->m_datalen); + if (mp->m_data == NULL) { + fprintf(stderr, "Error: %s: buffer alloc failed for sysctl metric \"%s\"\n", mp->m_pcpname, mp->m_name); + __pmNoMem("do_sysctl", mp->m_datalen, PM_FATAL_ERR); + /*NOTREACHED*/ + } + } + else + return -errno; + } + if (xpect > 0 && mp->m_datalen != xpect) { + fprintf(stderr, "Error: %s: sysctl(%s) datalen=%d not %d!\n", mp->m_pcpname, mp->m_name, (int)mp->m_datalen, (int)xpect); + return 0; + } + return mp->m_datalen; +} + +/* + * kernel memory reader setup + */ +struct nlist symbols[] = { + { .n_name = "_ifnet" }, + { .n_name = NULL } +}; +kvm_t *kvmp; + +static void +kmemread_init(void) +{ + int sts; + int i; + char errmsg[_POSIX2_LINE_MAX]; + + /* + * If we're running as a daemon PMDA, assume we're setgid kmem, + * so we can open /dev/kmem, and downgrade privileges after the + * kvm_open(). + * For a DSO PMDA, we have to assume pmcd has the required + * privileges and don't dink with them. + */ + kvmp = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errmsg); + if (!isDSO) + setgid(getgid()); + if (kvmp == NULL) { + fprintf(stderr, "kmemread_init: kvm_openfiles failed: %s\n", errmsg); + return; + } + + sts = kvm_nlist(kvmp, symbols); + if (sts < 0) { + fprintf(stderr, "kmemread_init: kvm_nlist failed: %s\n", pmErrStr(-errno)); + for (i = 0; i < sizeof(symbols)/sizeof(symbols[0])-1; i++) + symbols[i].n_value = 0; + return; + } +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) { + for (i = 0; i < sizeof(symbols)/sizeof(symbols[0])-1; i++) { + fprintf(stderr, "Info: kernel symbol %s found at 0x%08lx\n", symbols[i].n_name, symbols[i].n_value); + } + } +#endif + +} + +/* + * Callback provided to pmdaFetch ... come here once per metric-instance + * pair in each pmFetch(). + */ +static int +netbsd_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) +{ + int sts = PM_ERR_PMID; + __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); + mib_t *mp; + + mp = (mib_t *)mdesc->m_user; + if (idp->cluster == CL_SYSCTL) { + /* sysctl() simple cases */ + switch (idp->item) { + /* 32-bit integer values */ + case 0: /* hinv.ncpu */ + case 18: /* swap.pagesin */ + case 19: /* swap.pagesout */ + case 20: /* swap.in */ + case 21: /* swap.out */ + case 22: /* kernel.all.pswitch */ + case 23: /* kernel.all.syscall */ + case 24: /* kernel.all.intr */ + sts = do_sysctl(mp, sizeof(atom->ul)); + if (sts > 0) { + atom->ul = *((__uint32_t *)mp->m_data); + sts = 1; + } + break; + + /* 64-bit integer values */ + case 1: /* hinv.physmem */ + case 25: /* swap.length */ + case 26: /* swap.used */ + sts = do_sysctl(mp, sizeof(atom->ull)); + if (sts > 0) { + atom->ull = *((__uint64_t *)mp->m_data); + sts = 1; + } + break; + + /* string values */ + case 15: /* hinv.cpu.vendor */ + case 16: /* hinv.cpu.model */ + case 17: /* hinv.cpu.arch */ + sts = do_sysctl(mp, (size_t)0); + if (sts > 0) { + atom->cp = (char *)mp->m_data; + sts = 1; + } + break; + + /* structs and aggregates */ + case 2: /* kernel.all.load */ + sts = do_sysctl(mp, 3*sizeof(atom->d)); + if (sts > 0) { + int i; + struct loadavg *lp = (struct loadavg *)mp->m_data; + if (inst == 1) + i = 0; + else if (inst == 5) + i = 1; + else if (inst == 15) + i = 2; + else + return PM_ERR_INST; + atom->f = (float)((double)lp->ldavg[i] / lp->fscale); + sts = 1; + } + break; + + case 3: /* kernel.all.cpu.user */ + case 4: /* kernel.all.cpu.nice */ + case 5: /* kernel.all.cpu.sys */ + case 6: /* kernel.all.cpu.intr */ + case 7: /* kernel.all.cpu.idle */ + sts = do_sysctl(mp, CPUSTATES*sizeof(atom->ull)); + if (sts > 0) { + /* + * PMID assignment is important in the "-3" below so + * that metrics map to consecutive elements of the + * returned value in the order defined for CPUSTATES, + * i.e. CP_USER, CP_NICE, CP_SYS, CP_INTR and + * CP_IDLE + */ + atom->ull = 1000*((__uint64_t *)mp->m_data)[idp->item-3]/cpuhz; + sts = 1; + } + break; + + case 8: /* kernel.percpu.cpu.user */ + case 9: /* kernel.percpu.cpu.nice */ + case 10: /* kernel.percpu.cpu.sys */ + case 11: /* kernel.percpu.cpu.intr */ + case 12: /* kernel.percpu.cpu.idle */ + sts = do_sysctl(mp, ncpu*CPUSTATES*sizeof(atom->ull)); + if (sts > 0) { + /* + * PMID assignment is important in the "-8" below so + * that metrics map to consecutive elements of the + * returned value in the order defined for CPUSTATES, + * i.e. CP_USER, CP_NICE, CP_SYS, CP_INTR and + * CP_IDLE, and then there is one such set for each + * CPU up to the maximum number of CPUs installed in + * the system. + */ + atom->ull = 1000*((__uint64_t *)mp->m_data)[inst * CPUSTATES + idp->item-8]/cpuhz; + sts = 1; + } + break; + + case 13: /* kernel.all.hz */ + sts = do_sysctl(mp, sizeof(struct clockinfo)); + if (sts > 0) { + struct clockinfo *cp = (struct clockinfo *)mp->m_data; + atom->ul = cp->hz; + sts = 1; + } + break; + + } + } + else if (idp->cluster == CL_SPECIAL) { + /* special cases */ + switch (idp->item) { + case 0: /* hinv.ndisk */ + refresh_disk_metrics(); + atom->ul = pmdaCacheOp(indomtab[DISK_INDOM].it_indom, PMDA_CACHE_SIZE_ACTIVE); + sts = 1; + break; + + case 1: /* swap.free */ + /* first vm.swap_total */ + sts = do_sysctl(mp, sizeof(atom->ull)); + if (sts > 0) { + atom->ull = *((__uint64_t *)mp->m_data); + /* + * now subtract vm.swap_reserved ... assumes consecutive + * mib[] entries + */ + mp++; + sts = do_sysctl(mp, sizeof(atom->ull)); + if (sts > 0) { + atom->ull -= *((__uint64_t *)mp->m_data); + sts = 1; + } + } + break; + + case 3: /* hinv.pagesize */ + atom->ul = pagesize; + sts = 1; + break; + + case 4: /* mem.util.all */ + case 6: /* mem.util.free */ + case 8: /* mem.util.cached */ + case 9: /* mem.util.wired */ + case 10: /* mem.util.active */ + case 11: /* mem.util.inactive */ + sts = do_sysctl(mp, sizeof(atom->ul)); + if (sts > 0) { + atom->ul = *((__uint32_t *)mp->m_data) * (pagesize / 1024); + sts = 1; + } + break; + + case 7: /* mem.util.bufmem */ + sts = do_sysctl(mp, sizeof(atom->ul)); + if (sts > 0) { + atom->ul = *((__uint32_t *)mp->m_data) / 1024; + sts = 1; + } + break; + + case 5: /* mem.util.used */ + /* + * mp-> v_page_count entry in mib[] + * assuming consecutive mib[] entries, we want + * v_page_count mp[0] - v_free_count mp[1] - + * v_cache_count mp[2] - v_inactive_count mp[5] + */ + sts = do_sysctl(mp, sizeof(atom->ul)); + if (sts > 0) { + atom->ul = *((__uint32_t *)mp->m_data); + sts = do_sysctl(&mp[1], sizeof(atom->ul)); + if (sts > 0) { + atom->ul -= *((__uint32_t *)mp[1].m_data); + sts = do_sysctl(&mp[2], sizeof(atom->ul)); + if (sts > 0) { + atom->ul -= *((__uint32_t *)mp[2].m_data); + sts = do_sysctl(&mp[5], sizeof(atom->ul)); + if (sts > 0) { + atom->ul -= *((__uint32_t *)mp[5].m_data); + atom->ul *= (pagesize / 1024); + sts = 1; + } + } + } + } + break; + + case 12: /* mem.util.avail */ + /* + * mp-> v_page_count entry in mib[] + * assuming consecutive mib[] entries, we want + * v_free_count mp[1] + v_cache_count mp[2] + + * v_inactive_count mp[5] + */ + sts = do_sysctl(&mp[1], sizeof(atom->ul)); + if (sts > 0) { + atom->ul = *((__uint32_t *)mp[1].m_data); + sts = do_sysctl(&mp[2], sizeof(atom->ul)); + if (sts > 0) { + atom->ul += *((__uint32_t *)mp[2].m_data); + sts = do_sysctl(&mp[5], sizeof(atom->ul)); + if (sts > 0) { + atom->ul += *((__uint32_t *)mp[5].m_data); + atom->ul *= (pagesize / 1024); + sts = 1; + } + } + } + break; + + } + } + else if (idp->cluster == CL_DISK) { + /* disk metrics */ + sts = do_disk_metrics(mdesc, inst, atom); + } + else if (idp->cluster == CL_NETIF) { + /* network interface metrics */ + sts = do_netif_metrics(mdesc, inst, atom); + } + + return sts; +} + +/* + * wrapper for pmdaFetch ... force value caches to be reloaded if needed, + * then do the fetch + */ +static int +netbsd_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) +{ + int i; + int done_disk = 0; + int done_netif = 0; + + for (i = 0; i < maplen; i++) { + map[i].m_fetched = 0; + } + + /* + * pre-fetch all metrics if needed, and update instance domains if + * they have changed + */ + for (i = 0; !done_disk && !done_netif && i < numpmid; i++) { + if (pmid_cluster(pmidlist[i]) == CL_DISK) { + refresh_disk_metrics(); + done_disk = 1; + } + else if (pmid_cluster(pmidlist[i]) == CL_NETIF) { + refresh_netif_metrics(); + done_netif = 1; + } + } + + return pmdaFetch(numpmid, pmidlist, resp, pmda); +} + +/* + * wrapper for pmdaInstance ... refresh required instance domain first + */ +static int +netbsd_instance(pmInDom indom, int inst, char *name, __pmInResult **result, pmdaExt *pmda) +{ + /* + * indomtab[] instance names and ids are not used for some indoms, + * ensure pmdaCache is current + */ + if (indom == indomtab[DISK_INDOM].it_indom) + refresh_disk_metrics(); + if (indom == indomtab[NETIF_INDOM].it_indom) + refresh_netif_metrics(); + + return pmdaInstance(indom, inst, name, result, pmda); +} + +/* + * PCP metric name matching for linking metrictab[] entries to mib[] + * entries. + * + * Return 1 if prefix[] is equal to, or a prefix of name[] + * + * prefix[] of the form "a.bc" or "a.bc*" matches a name[] like "a.bc" + * or "a.bcanything", to improve readability of the initializers in + * mib[], and asterisk is a "match all" special case, so "a.b.*" matches + * "a.b.anything" + */ +static int +matchname(const char *prefix, const char *name) +{ + while (*prefix != '\0' && *name != '\0' && *prefix == *name) { + prefix++; + name++; + } + if (*prefix == '\0' || *prefix == '*') + return 1; + else + return 0; +} + +/* + * Initialise the agent (both daemon and DSO). + * + * Do mapping from sysclt(3) names to mibs. + * Collect some global constants. + * Build the system-specific, but not dynamic, instance domains, + * e.g. CPU_INDOM. + * Initialize the kernel memory reader. + */ +void +netbsd_init(pmdaInterface *dp) +{ + int i; + int m; + int sts; + struct clockinfo clockrates; + size_t sz; + int mib[CTL_MAXNAME]; /* enough for longest mib key */ + char iname[16]; /* enough for cpuNN.. */ + + if (isDSO) { + char mypath[MAXPATHLEN]; + int sep = __pmPathSeparator(); + snprintf(mypath, sizeof(mypath), "%s%c" "netbsd" "%c" "help", + pmGetConfig("PCP_PMDAS_DIR"), sep, sep); + pmdaDSO(dp, PMDA_INTERFACE_5, "netbsd DSO", mypath); + } else { + __pmSetProcessIdentity(username); + } + + if (dp->status != 0) + return; + + dp->version.four.fetch = netbsd_fetch; + dp->version.four.instance = netbsd_instance; + + pmdaSetFetchCallBack(dp, netbsd_fetchCallBack); + + pmdaInit(dp, indomtab, indomtablen, metrictab, metrictablen); + + /* + * Link metrictab[] entries via m_user to map[] entries based on + * matching sysctl(3) name + * + * also translate the sysctl(3) name to a mib + */ + for (m = 0; m < metrictablen; m++) { + if (metrictab[m].m_user == NULL) { + /* not using sysctl(3) */ + continue; + } + for (i = 0; i < maplen; i++) { + if (matchname(map[i].m_pcpname, (char *)metrictab[m].m_user)) { + if (map[i].m_mib == NULL) { + /* + * multiple metrictab[] entries may point to the same + * mib[] entry, but this is the first time for this + * mib[] entry ... + */ + map[i].m_miblen = sizeof(mib); + sts = sysctlnametomib(map[i].m_name, mib, &map[i].m_miblen); + if (sts == 0) { + map[i].m_mib = (int *)malloc(map[i].m_miblen*sizeof(map[i].m_mib[0])); + if (map[i].m_mib == NULL) { + fprintf(stderr, "Error: %s (%s): failed mib alloc for sysctl metric \"%s\"\n", map[i].m_pcpname, pmIDStr(metrictab[m].m_desc.pmid), map[i].m_name); + __pmNoMem("netbsd_init: mib", map[i].m_miblen*sizeof(map[i].m_mib[0]), PM_FATAL_ERR); + /*NOTREACHED*/ + } + memcpy(map[i].m_mib, mib, map[i].m_miblen*sizeof(map[i].m_mib[0])); + } + else { + fprintf(stderr, "Error: %s (%s): failed sysctlnametomib(\"%s\", ...): %s\n", map[i].m_pcpname, pmIDStr(metrictab[m].m_desc.pmid), map[i].m_name, pmErrStr(-errno)); + metrictab[m].m_user = (void *)&bad_mib; + } + } +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) { + int p; + fprintf(stderr, "Info: %s (%s): sysctl metric \"%s\" -> ", (char *)metrictab[m].m_user, pmIDStr(metrictab[m].m_desc.pmid), map[i].m_name); + for (p = 0; p < map[i].m_miblen; p++) { + if (p > 0) fputc('.', stderr); + fprintf(stderr, "%d", map[i].m_mib[p]); + } + fputc('\n', stderr); + } +#endif + metrictab[m].m_user = (void *)&map[i]; + break; + } + } + if (i == maplen) { + fprintf(stderr, "Error: %s (%s): cannot match name in sysctl map[]\n", (char *)metrictab[m].m_user, pmIDStr(metrictab[m].m_desc.pmid)); + metrictab[m].m_user = (void *)&bad_mib; + } + } + + /* + * Collect some global constants needed later ... + */ + sz = sizeof(clockrates); + sts = sysctlbyname("kern.clockrate", &clockrates, &sz, NULL, 0); + if (sts < 0) { + fprintf(stderr, "Fatal Error: sysctlbyname(\"kern.clockrate\", ...) failed: %s\n", pmErrStr(-errno)); + exit(1); + } + cpuhz = clockrates.stathz; +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) + fprintf(stderr, "Info: CPU time \"hz\" = %d\n", cpuhz); +#endif + + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + sz = sizeof(ncpu); + sts = sysctl(mib, 2, &ncpu, &sz, NULL, 0); +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) + fprintf(stderr, "Info: ncpu = %d\n", ncpu); +#endif + + sz = sizeof(pagesize); + sts = sysctlbyname("hw.pagesize", &pagesize, &sz, NULL, 0); + if (sts < 0) { + fprintf(stderr, "Fatal Error: sysctlbyname(\"hw.pagesize\", ...) failed: %s\n", pmErrStr(-errno)); + exit(1); + } +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) + fprintf(stderr, "Info: VM pagesize = %d\n", pagesize); +#endif + + /* + * Build some instance domains ... + */ + indomtab[CPU_INDOM].it_numinst = ncpu; + indomtab[CPU_INDOM].it_set = (pmdaInstid *)malloc(ncpu * sizeof(pmdaInstid)); + if (indomtab[CPU_INDOM].it_set == NULL) { + __pmNoMem("netbsd_init: CPU_INDOM it_set", ncpu * sizeof(pmdaInstid), PM_FATAL_ERR); + /*NOTREACHED*/ + } + for (i = 0; i < ncpu; i++) { + indomtab[CPU_INDOM].it_set[i].i_inst = i; + snprintf(iname, sizeof(iname), "cpu%d", i); + indomtab[CPU_INDOM].it_set[i].i_name = strdup(iname); + if (indomtab[CPU_INDOM].it_set[i].i_name == NULL) { + __pmNoMem("netbsd_init: CPU_INDOM strdup iname", strlen(iname), PM_FATAL_ERR); + /*NOTREACHED*/ + } + } + + kmemread_init(); +} + +static void +usage(void) +{ + fprintf(stderr, "Usage: %s [options]\n\n", pmProgname); + fputs("Options:\n" + " -d domain use domain (numeric) for metrics domain of PMDA\n" + " -l logfile write log into logfile rather than using default log name\n" + " -U username user account to run under (default \"pcp\")\n" + "\nExactly one of the following options may appear:\n" + " -i port expect PMCD to connect on given inet port (number or name)\n" + " -p expect PMCD to supply stdin/stdout (pipe)\n" + " -u socket expect PMCD to connect on given unix domain socket\n" + " -6 port expect PMCD to connect on given ipv6 port (number or name)\n", + stderr); + exit(1); +} + +/* + * Set up the agent if running as a daemon. + */ +int +main(int argc, char **argv) +{ + int c, err = 0; + int sep = __pmPathSeparator(); + pmdaInterface dispatch; + char mypath[MAXPATHLEN]; + + isDSO = 0; + __pmSetProgname(argv[0]); + __pmGetUsername(&username); + + snprintf(mypath, sizeof(mypath), "%s%c" "netbsd" "%c" "help", + pmGetConfig("PCP_PMDAS_DIR"), sep, sep); + pmdaDaemon(&dispatch, PMDA_INTERFACE_5, pmProgname, NETBSD, + "netbsd.log", mypath); + + while ((c = pmdaGetOpt(argc, argv, "D:d:i:l:pu:U:6:?", &dispatch, &err)) != EOF) { + switch(c) { + case 'U': + username = optarg; + break; + default: + err++; + } + } + if (err) + usage(); + + pmdaOpenLog(&dispatch); + netbsd_init(&dispatch); + pmdaConnect(&dispatch); + pmdaMain(&dispatch); + exit(0); +} diff --git a/src/pmdas/netbsd/netbsd.h b/src/pmdas/netbsd/netbsd.h new file mode 100644 index 0000000..c6b9b72 --- /dev/null +++ b/src/pmdas/netbsd/netbsd.h @@ -0,0 +1,44 @@ +/* + * + * Copyright (c) 2012 Ken McDonell All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * instance domains control + */ +#define LOADAV_INDOM 0 +#define CPU_INDOM 1 +#define DISK_INDOM 2 +#define NETIF_INDOM 3 +extern pmdaIndom indomtab[]; + +extern void refresh_disk_metrics(void); +extern int do_disk_metrics(pmdaMetric *, unsigned int, pmAtomValue *); + +extern void refresh_netif_metrics(void); +extern int do_netif_metrics(pmdaMetric *, unsigned int, pmAtomValue *); + +/* + * kernel memory reader pieces + */ +#include <kvm.h> +#include <nlist.h> + +extern kvm_t *kvmp; + +#define KERN_IFNET 0 +extern struct nlist symbols[]; diff --git a/src/pmdas/netbsd/netif.c b/src/pmdas/netbsd/netif.c new file mode 100644 index 0000000..19737bb --- /dev/null +++ b/src/pmdas/netbsd/netif.c @@ -0,0 +1,233 @@ +/* + * NetBSD Kernel PMDA - network interface metrics + * + * Copyright (c) 2012,2013 Ken McDonell. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "pmapi.h" +#include "impl.h" +#include "pmda.h" + +#if 0 +#include <sys/types.h> +#include <sys/socket.h> +#include <net/if.h> +#include <net/if_var.h> +#include <net/if_types.h> +#endif + +#include "netbsd.h" + +#define WARN_INIT 1 +#define WARN_READ_HEAD 2 + +void +refresh_netif_metrics(void) +{ +#if 0 + int i; + int sts; + unsigned long kaddr; + struct ifnethead ifnethead; + struct ifnet ifnet; + struct ifnet *ifp; + static int warn = 0; /* warn once control */ + + /* + * Not sure that the order of chained netif structs is invariant, + * especially if interfaces are added to the configuration after + * initial system boot ... so mark all the instances as inactive + * and re-match based on the interface name + */ + pmdaCacheOp(indomtab[NETIF_INDOM].it_indom, PMDA_CACHE_INACTIVE); + + kaddr = symbols[KERN_IFNET].n_value; + if (kvmp == NULL || kaddr == 0) { + /* no network interface metrics for us today ... */ + if ((warn & WARN_INIT) == 0) { + fprintf(stderr, "refresh_netif_metrics: Warning: cannot get any network interface metrics\n"); + warn |= WARN_INIT; + } + return; + } + + /* + * Kernel data structures for the linked list of network interface + * information. + * + * _ifnet -> struct ifnethead { + * struct ifnet *tqh_first; + * struct ifnet **tqh_last; + * ... + * } + * + * and within an ifnet struct (declared in <net/if_var.h>) we find + * the linked list maintained in if_link, the external interface + * name in if_xname[] and if_data which is a nested if_data stuct + * (declared in <net/if.h>) that contains many of the goodies we're + * after, e.g. u_char ifi_type, u_long ifi_mtu, u_long ifi_baudrate, + * u_long ifi_ipackets, u_long ifi_opackets, u_long ifi_ibytes, + * u_long ifi_obytes, etc. + */ + if (kvm_read(kvmp, kaddr, (char *)&ifnethead, sizeof(ifnethead)) != sizeof(ifnethead)) { + if ((warn & WARN_READ_HEAD) == 0) { + fprintf(stderr, "refresh_netif_metrics: Warning: kvm_read: ifnethead: %s\n", kvm_geterr(kvmp)); + warn |= WARN_READ_HEAD; + } + return; + } + + for (i = 0; ; i++) { + if (i == 0) + kaddr = (unsigned long)TAILQ_FIRST(&ifnethead); + else + kaddr = (unsigned long)TAILQ_NEXT(&ifnet, if_link); + + if (kaddr == 0) + break; + + if (kvm_read(kvmp, kaddr, (char *)&ifnet, sizeof(ifnet)) != sizeof(ifnet)) { + fprintf(stderr, "refresh_netif_metrics: Error: kvm_read: ifnet[%d]: %s\n", i, kvm_geterr(kvmp)); + return; + } + + /* skip network interfaces that are not interesting ... */ + if (strcmp(ifnet.if_xname, "lo0") == 0) + continue; + + sts = pmdaCacheLookupName(indomtab[NETIF_INDOM].it_indom, ifnet.if_xname, NULL, (void **)&ifp); + if (sts == PMDA_CACHE_ACTIVE) { + fprintf(stderr, "refresh_netif_metrics: Warning: duplicate name (%s) in network interface indom\n", ifnet.if_xname); + continue; + } + else if (sts == PMDA_CACHE_INACTIVE) { + /* reactivate an existing entry */ + pmdaCacheStore(indomtab[NETIF_INDOM].it_indom, PMDA_CACHE_ADD, ifnet.if_xname, (void *)ifp); + } + else { + /* new entry */ + ifp = (struct ifnet *)malloc(sizeof(*ifp)); + if (ifp == NULL) { + fprintf(stderr, "Error: struct ifnet alloc failed for network interface \"%s\"\n", ifnet.if_xname); + __pmNoMem("refresh_netif_metrics", sizeof(*ifp), PM_FATAL_ERR); + /*NOTREACHED*/ + } + pmdaCacheStore(indomtab[NETIF_INDOM].it_indom, PMDA_CACHE_ADD, ifnet.if_xname, (void *)ifp); + } + memcpy((void *)ifp, (void *)&ifnet, sizeof(*ifp)); + } +#endif +} + +int +do_netif_metrics(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) +{ +#if 0 + struct ifnet *ifp; + int sts; + + if (inst != PM_IN_NULL) { + /* + * per-network interface metrics + */ + sts = pmdaCacheLookup(indomtab[NETIF_INDOM].it_indom, inst, NULL, (void **)&ifp); + if (sts == PMDA_CACHE_ACTIVE) { + sts = 1; + /* cluster and domain already checked, just need item ... */ + switch (pmid_item(mdesc->m_desc.pmid)) { + case 0: /* network.interface.mtu */ + atom->ul = (__uint32_t)ifp->if_data.ifi_mtu; + break; + + case 1: /* network.interface.up */ + atom->ul = (ifp->if_flags & IFF_UP) == IFF_UP; + break; + + case 2: /* network.interface.baudrate */ + atom->ull = ifp->if_data.ifi_baudrate; + break; + + case 3: /* network.interface.in.bytes */ + atom->ull = ifp->if_data.ifi_ibytes; + break; + + case 4: /* network.interface.in.packets */ + atom->ull = ifp->if_data.ifi_ipackets; + break; + + case 5: /* network.interface.in.mcasts */ + atom->ull = ifp->if_data.ifi_imcasts; + break; + + case 6: /* network.interface.in.errors */ + atom->ull = ifp->if_data.ifi_ierrors; + break; + + case 7: /* network.interface.in.drops */ + atom->ull = ifp->if_data.ifi_iqdrops; + break; + + case 8: /* network.interface.out.bytes */ + atom->ull = ifp->if_data.ifi_obytes; + break; + + case 9: /* network.interface.out.packets */ + atom->ull = ifp->if_data.ifi_opackets; + break; + + case 10: /* network.interface.out.mcasts */ + atom->ull = ifp->if_data.ifi_omcasts; + break; + + case 11: /* network.interface.out.errors */ + atom->ull = ifp->if_data.ifi_oerrors; + break; + + case 12: /* network.interface.out.collisions */ + atom->ull = ifp->if_data.ifi_collisions; + break; + + case 13: /* network.interface.total.bytes */ + atom->ull = ifp->if_data.ifi_ibytes + ifp->if_data.ifi_obytes; + break; + + case 14: /* network.interface.total.packets */ + atom->ull = ifp->if_data.ifi_ipackets + ifp->if_data.ifi_opackets; + break; + + case 15: /* network.interface.total.mcasts */ + atom->ull = ifp->if_data.ifi_imcasts + ifp->if_data.ifi_omcasts; + break; + + case 16: /* network.interface.total.errors */ + atom->ull = ifp->if_data.ifi_ierrors + ifp->if_data.ifi_oerrors; + break; + + default: + sts = PM_ERR_PMID; + break; + } + } + else + sts = 0; + } + + return sts; +#else + return PM_ERR_PMID; +#endif +} diff --git a/src/pmdas/netbsd/root_netbsd b/src/pmdas/netbsd/root_netbsd new file mode 100644 index 0000000..c05ce4a --- /dev/null +++ b/src/pmdas/netbsd/root_netbsd @@ -0,0 +1,172 @@ +/* + * Metrics for NetBSD kernel PMDA + * + * Copyright (c) 2012 Ken McDonell All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/* + * the domain for the NETBSD PMDA ... + */ +#ifndef NETBSD +#define NETBSD 116 +#endif + +root { + hinv + kernel + disk + mem + network + swap +} + +hinv { + ncpu NETBSD:0:0 + ndisk NETBSD:1:0 + physmem NETBSD:0:1 + pagesize NETBSD:1:3 + cpu +} + +hinv.cpu { + vendor NETBSD:0:15 + model NETBSD:0:16 + arch NETBSD:0:17 +} + +kernel { + all + percpu +} + +kernel.all { + pswitch NETBSD:0:22 + syscall NETBSD:0:23 + intr NETBSD:0:24 + hz NETBSD:0:13 + load NETBSD:0:2 + cpu +} + +kernel.all.cpu { + user NETBSD:0:3 + nice NETBSD:0:4 + sys NETBSD:0:5 + intr NETBSD:0:6 + idle NETBSD:0:7 +} + +kernel.percpu { + cpu +} + +kernel.percpu.cpu { + user NETBSD:0:8 + nice NETBSD:0:9 + sys NETBSD:0:10 + intr NETBSD:0:11 + idle NETBSD:0:12 +} + +disk { + dev + all +} + +disk.dev { + read NETBSD:2:0 + write NETBSD:2:1 + total NETBSD:2:2 + read_bytes NETBSD:2:3 + write_bytes NETBSD:2:4 + total_bytes NETBSD:2:5 + blkread NETBSD:2:12 + blkwrite NETBSD:2:13 + blktotal NETBSD:2:14 +} + +disk.all { + read NETBSD:2:6 + write NETBSD:2:7 + total NETBSD:2:8 + read_bytes NETBSD:2:9 + write_bytes NETBSD:2:10 + total_bytes NETBSD:2:11 + blkread NETBSD:2:15 + blkwrite NETBSD:2:16 + blktotal NETBSD:2:17 +} + +mem { + util +} + +mem.util { + all NETBSD:1:4 + used NETBSD:1:5 + free NETBSD:1:6 + bufmem NETBSD:1:7 + cached NETBSD:1:8 + wired NETBSD:1:9 + active NETBSD:1:10 + inactive NETBSD:1:11 + avail NETBSD:1:12 +} + +network { + interface +} + +network.interface { + mtu NETBSD:3:0 + up NETBSD:3:1 + baudrate NETBSD:3:2 + in + out + total +} + +network.interface.in { + bytes NETBSD:3:3 + packets NETBSD:3:4 + mcasts NETBSD:3:5 + errors NETBSD:3:6 + drops NETBSD:3:7 +} + +network.interface.out { + bytes NETBSD:3:8 + packets NETBSD:3:9 + mcasts NETBSD:3:10 + errors NETBSD:3:11 + collisions NETBSD:3:12 +} + +network.interface.total { + bytes NETBSD:3:13 + packets NETBSD:3:14 + mcasts NETBSD:3:15 + errors NETBSD:3:16 +} + +swap { + pagesin NETBSD:0:18 + pagesout NETBSD:0:19 + in NETBSD:0:20 + out NETBSD:0:21 + length NETBSD:0:25 + used NETBSD:0:26 + free NETBSD:1:1 +} + +#undef NETBSD |