Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
456 lines (364 sloc) 16.9 KB
package kstat
import ""
Package kstat provides a Go interface to the Solaris/OmniOS kstat(s)
system for user-level access to a lot of kernel statistics. For more
documentation on kstats, see kstat(1) and kstat(3kstat).
The package can retrieve what are called 'named' kstat statistics, IO
statistics, and the most common additional types of 'raw' statistics,
which covers almost all kstats you will normally find in the kernel. You
can see the names and types of other kstats, but not currently retrieve
data for them. Named statistics are the most common type for general
information; IO statistics are exported by disks and some other things.
Supported additional raw kstats are unix:0:sysinfo, unix:0:vminfo,
unix:0:var, and mnt:*:mntinfo.
General usage for named statistics: call Open() to obtain a Token, then
call GetNamed() on it to obtain Named(s) for specific statistics. Note
that this always gives you the very latest value for the statistic. If
you want a number of statistics from the same module:inst:name triplet
(eg several network counters from the same network interface) and you
want them to all have been gathered at the same time, you need to call
.Lookup() to obtain a KStat and then repeatedly call its .GetNamed()
(this is also slightly more efficient).
The short version: a kstat is a collection of some related statistics,
eg various network counters for a particular network interface. A Token
is a handle for a collection of kstats. You go collection (Token) ->
kstat (KStat) -> specific statistic (Named) in order to retrieve the
value of a specific statistic.
(IO stats are retrieved all at once with GetIO(), because they come to
us from the kernel as one single struct so that's what you get.)
This is a cgo-based package. Cross compilation is up to you. Goroutine
safety is in no way guaranteed because the underlying C kstat library is
probably not thread or goroutine safe (and there are some all-Go
concurrency races involving .Close()).
This package may leak memory, especially since the Solaris kstat manpage
is not clear on the requirements here. However I believe it's reasonably
memory safe. It's possible to totally corrupt memory with use-after-free
errors if you do operations on kstats after calling Token.Close(),
although we try to avoid that.
NOTE: this package is quite young. The API may well change as I (and
other people) gain more experience with it.
In general this is not going to be as lean and mean as calling C
directly, partly because of intrinsic CGo overheads and partly because
we do more memory allocation and deallocation than a C program would
(partly because we prioritize not leaking memory).
We support named kstats and IO kstats (KSTAT_TYPE_NAMED and
KSTAT_TYPE_IO / kstat_io_t respectively). kstat(1) also knows about a
number of magic specific 'raw' stats (which are generally custom C
structs); of these we support unix:0:sysinfo, unix:0:vminfo, unix:0:var,
and mnt:*:mntinfo for NFS filesystem mounts.
In theory kstat supports general timer and interrupt stats. In practice
there is no use of KSTAT_TYPE_TIMER in the current Illumos kernel source
and very little use of KSTAT_TYPE_INTR (mostly by very old hardware
drivers, although the vioif driver uses it too). Since I can't test
KSTAT_TYPE_INTR stats, we don't currently support it.
There are also a few additional KSTAT_TYPE_RAW raw stats that we don't
support, mostly because they seem to be effectively obsolete. These
specific raw stats can be found listed in the Illumos source code in
cmd/stat/kstat/kstat.h in the ks_raw_lookup array. See
cmd/stat/kstat/kstat.c for how they're interpreted. If you need access
to one of these kstats, the KStat.CopyTo() and KStat.Raw() methods give
you an escape hatch to roll your own. You'll probably need to use cgo to
generate an appropriate Go struct that matches the C struct you need. My
notes on this process may be helpful:
Author: Chris Siebenmann
Copyright: standard Go copyright.
(If you're reading this documentation on a non-Solaris platform, you're
probably not seeing the detailed API documentation for constants, types,
and so on because of tooling limitations in godoc et al.)
func CFieldString(src []int8) string
CFieldString converts a (null-terminated) C string embedded in an []int8
slice to a (Go) string. The []int8 slice is likely to come from an
[N]int8 fixed-size field in a statistics struct. If there is no null in
the slice, the entire slice is returned.
(The no-null behavior is common in C APIs; a string is often allowed to
exactly fill the field with no room for a trailing null.)
type IO struct {
Nread uint64
Nwritten uint64
Reads uint32
Writes uint32
Wtime int64
Wlentime int64
Wlastupdate int64
Rtime int64
Rlentime int64
Rlastupdate int64
Wcnt uint32
Rcnt uint32
IO represents the entire collection of KStat (disk) IO statistics
exposed by an IoStat type KStat.
Because IO is an exact copy of the C kstat_io_t structure from the
kernel, it does not have a Snaptime or KStat field. You must save that
information separately if you need it, perhaps by embedded the IO struct
as an anonymous struct in an additional struct of your own.
type KSType int
KSType is the type of the data in a KStat.
const (
The different types of data that a KStat may contain, ie these are the
value of a KStat.Type. We currently only support getting Named and IO
func (tp KSType) String() string
type KStat struct {
Module string
Instance int
Name string
// Class is eg 'net' or 'disk'. In kstat(1) it shows up as a
// ':class' statistic.
Class string
// Type is the type of kstat.
Type KSType
// Creation time of a kstat in nanoseconds since sometime.
// See gethrtime(3) and kstat(3kstat).
Crtime int64
// Snaptime is what kstat(1) reports as 'snaptime', the time
// that this data was obtained. As with Crtime, it is in
// nanoseconds since some arbitrary point in time.
// Snaptime may not be valid until .Refresh() or .GetNamed()
// has been called.
Snaptime int64
// contains filtered or unexported fields
KStat is the access handle for the collection of statistics for a
particular module:instance:name kstat.
func (k *KStat) AllNamed() ([]*Named, error)
AllNamed returns an array of all named statistics for a particular
named-type KStat. Entries are returned in no particular order.
func (k *KStat) CopyTo(ptr interface{}) error
CopyTo copies a RawStat KStat into a struct that you supply a pointer
to. The size of the struct must exactly match the size of the RawStat's
CopyStat imposes conditions on the struct that you are copying to: it
must be composed entirely of primitive integer types with defined sizes
(intN and uintN), or arrays and structs that ultimately only contain
them. All fields should be exported.
If you give CopyStat a bad argument, it generally panics.
This API is provisional and may be changed or deleted.
func (k *KStat) GetIO() (*IO, error)
GetIO retrieves the IO statistics data from an IoStat type KStat. It
always refreshes the KStat to provide current data.
It corresponds to kstat_read() followed by getting a copy of ks_data
(which is a kstat_io_t).
func (k *KStat) GetMntinfo() (*Mntinfo, error)
GetMntinfo retrieves a Mntinfo struct from a nfs:*:mntinfo KStat. It
does not force a refresh of the KStat.
func (k *KStat) GetNamed(name string) (*Named, error)
GetNamed obtains a particular named statistic from a KStat. It does not
refresh the KStat's statistics data, so multiple calls to GetNamed on a
single KStat will get a coherent set of statistic values from it.
It corresponds to kstat_data_lookup().
func (k *KStat) Raw() (*Raw, error)
Raw returns the raw byte data of a KStat. It may be called on any KStat.
It does not refresh the KStat's data.
func (k *KStat) Refresh() error
Refresh the statistics data for a KStat.
Note that this does not update any existing Named objects for statistics
from this KStat. You must re-do .GetNamed() to get new ones in order to
see any updates.
Under the hood this does a kstat_read(). You don't need to call it
explicitly before obtaining statistics from a KStat.
func (k *KStat) String() string
func (k *KStat) Valid() bool
Valid returns true if a KStat is still valid after a Token.Update() call
has returned true. If a KStat becomes invalid after an update, its
fields remain available but you can no longer call methods on it. You
may be able to look it up again with token.Lookup(k.Module, k.Instance,
k.Name), although it's possible that the module:instance:name now refers
to something else. Even if it is still the same thing, there is no
continuity in the actual statistics once Valid becomes false; you must
restart tracking from scratch.
(For example, if one disk is removed from the system and another is
added, the new disk may use the same module:instance:name as some of the
old disk's KStats. Your .Lookup() may succeed, but what you get back is
not in any way a continuation of the old disk's information.)
Valid also returns false after the KStat's token has been closed.
type Mntinfo struct {
RProto [128]int8
Vers uint32
Flags uint32
Secmod uint32
Curread uint32
Curwrite uint32
Timeo int32
Retrans int32
Acregmin uint32
Acregmax uint32
Acdirmin uint32
Acdirmax uint32
Timers [4]struct {
Srtt uint32
Deviate uint32
Rtxcur uint32
Noresponse uint32
Failover uint32
Remap uint32
RCurserver [257]int8
// contains filtered or unexported fields
Mntinfo is the kernel data from nfs:*:mntinfo, which is a 'struct
mntinfo_kstat'. Use .Proto() and .Curserver() to get the RProto and
RCurserver fields as strings instead of their awkward raw form.
func (m Mntinfo) Curserver() string
Curserver returns a Mntinfo RCurserver as a string.
func (m Mntinfo) Proto() string
Proto returns a Mntinfo RProto as a string.
type Named struct {
Name string
Type NamedType
// Only one of the following values is valid; the others are zero
// values.
// StringVal holds the value for both CharData and String Type(s).
StringVal string
IntVal int64
UintVal uint64
// The Snaptime this Named was obtained. Note that while you
// use the parent KStat's Crtime, you cannot use its Snaptime.
// The KStat may have been refreshed since this Named was
// created, which updates the Snaptime.
Snaptime int64
// Pointer to the parent KStat, for access to the full name
// and the crtime associated with this Named.
KStat *KStat
Named represents a particular kstat named statistic, ie the full
and its current value.
Name and Type are always valid, but only one of StringVal, IntVal, or
UintVal is valid for any particular statistic; which one is valid is
determined by its Type. Generally you'll already know what type a given
named kstat statistic is; I don't believe Solaris changes their type
once they're defined.
func (ks *Named) String() string
type NamedType int
NamedType represents the various types of named kstat statistics.
const (
CharData NamedType = C.KSTAT_DATA_CHAR
Int32 NamedType = C.KSTAT_DATA_INT32
Uint32 NamedType = C.KSTAT_DATA_UINT32
Int64 NamedType = C.KSTAT_DATA_INT64
Uint64 NamedType = C.KSTAT_DATA_UINT64
String NamedType = C.KSTAT_DATA_STRING
The different types of data that a named kstat statistic can be (ie,
these are the potential values of Named.Type).
func (tp NamedType) String() string
type Raw struct {
Data []byte
Ndata uint64
Snaptime int64
KStat *KStat
Raw is the raw data of a KStat. The actual bytes are in Data; Ndata is
kstat_t.ks_ndata, and is not normally useful.
Note that with RawStat KStats, it turns out that Ndata == len(Data).
This is contrary to its meaning for other types of kstats.
type Sysinfo struct {
Updates uint32
Runque uint32
Runocc uint32
Swpque uint32
Swpocc uint32
Waiting uint32
Sysinfo is the data from unix:0:sysinfo, which is a sysinfo_t.
type Token struct {
// contains filtered or unexported fields
Token is an access token for obtaining kstats.
func Open() (*Token, error)
Open returns a kstat Token that is used to obtain kstats. It corresponds
to kstat_open(). You should call .Close() when you're done and then not
use any KStats or Nameds obtained through this token.
(Failing to call .Close() will cause memory leaks.)
func (t *Token) All() []*KStat
All returns an array of all available KStats.
(It has no error return because due to how kstats are implemented, it
cannot fail.)
func (t *Token) Close() error
Close a kstat access token. A closed token cannot be used for anything
and cannot be reopened.
After a Token has been closed it remains safe to look at fields on KStat
and Named objects obtained through the Token, but it is not safe to call
methods on them other than String(); doing so may cause memory
corruption, although we try to avoid that.
This corresponds to kstat_close().
func (t *Token) GetNamed(module string, instance int, name, stat string) (*Named, error)
GetNamed obtains the Named representing a particular (named) kstat
module:instance:name:statistic statistic. It always returns current data
for the kstat statistic, even if it's called repeatedly for the same
It is equivalent to .Lookup() then KStat.GetNamed().
func (t *Token) Lookup(module string, instance int, name string) (*KStat, error)
Lookup looks up a particular kstat. module and name may be "" and
instance may be -1 to mean 'the first one that kstats can find'. It also
refreshes (or retrieves) the kstat's data and thus sets Snaptime.
Lookup() corresponds to kstat_lookup() *plus kstat_read()*.
func (tok *Token) Sysinfo() (*KStat, *Sysinfo, error)
Sysinfo returns the KStat and the statistics from unix:0:sysinfo. It
always returns a current, refreshed copy.
func (t *Token) Update() (bool, error)
Update synchronizes the Token to the current state of available kernel
kstats, returning true if the kernel's list of available kstats changed
and false otherwise. If there have been no changes in the kernel's kstat
list, all KStats remain valid. If there was a kstat update, some or all
of the KStats obtained through the Token may now be invalid. Some of the
now-invalid KStats may still exist and be the same thing, but if so they
will have to be looked up again.
(This happens if, for example, a device disappears and then reappears.
At the kernel level, the device's kstat is deleted when it disappears
and then is recreated when it reappears; the kernel considers the
recreated version to be a different kstat, although it has the same
module:instance:name. Note that the same module:instance:name still
existing does not guarantee that the kstat is for the same thing; one
disk might have removed and then an entirely different new disk added.)
Update corresponds to kstat_chain_update().
func (tok *Token) Var() (*KStat, *Var, error)
Var returns the KStat and the statistics from unix:0:var. It always
returns a current, refreshed copy.
func (tok *Token) Vminfo() (*KStat, *Vminfo, error)
Vminfo returns the KStat and the statistics from unix:0:vminfo. It
always returns a current, refreshed copy.
type Var struct {
Buf int32
Call int32
Proc int32
Maxupttl int32
Nglobpris int32
Maxsyspri int32
Clist int32
Maxup int32
Hbuf int32
Hmask int32
Pbuf int32
Sptmap int32
Maxpmem int32
Autoup int32
Bufhwm int32
Var is the data from unix:0:var, which is a 'struct var'.
type Vminfo struct {
Freemem uint64
Resv uint64
Alloc uint64
Avail uint64
Free uint64
Updates uint64
Vminfo is the data from unix:0:vminfo, which is a vminfo_t.