From 7fbdd0ae93bc792d103b39ffcd5bb92b270f8e35 Mon Sep 17 00:00:00 2001
From: mknapphrt <39998367+mknapphrt@users.noreply.github.com>
Date: Mon, 4 Feb 2019 10:54:41 -0500
Subject: [PATCH] Update procfs vendor (#1248)

Signed-off-by: Mark Knapp <mknapp@hudson-trading.com>
---
 CHANGELOG.md                                  |   3 +
 collector/cpu_linux.go                        |  84 ++-
 collector/fixtures/e2e-64k-page-output.txt    |  36 +-
 collector/fixtures/e2e-output.txt             |  36 +-
 go.mod                                        |   2 +-
 go.sum                                        |   4 +-
 .../prometheus/procfs/MAINTAINERS.md          |   3 +-
 vendor/github.com/prometheus/procfs/Makefile  |  57 +-
 .../prometheus/procfs/Makefile.common         | 223 ++++++
 vendor/github.com/prometheus/procfs/go.mod    |   1 +
 .../prometheus/procfs/internal/util/parse.go  |  14 +
 .../prometheus/procfs/mountstats.go           |  10 +
 .../github.com/prometheus/procfs/proc_stat.go |   4 +-
 .../prometheus/procfs/sysfs/class_thermal.go  |  99 +++
 .../prometheus/procfs/sysfs/fixtures.ttar     |  49 ++
 .../prometheus/procfs/sysfs/system_cpu.go     |  72 +-
 .../github.com/prometheus/procfs/xfs/parse.go |  18 +-
 .../github.com/siebenmann/go-kstat/.gitignore |   1 +
 .../github.com/siebenmann/go-kstat/Makefile   |   5 +
 vendor/github.com/siebenmann/go-kstat/README  |  37 +
 vendor/github.com/siebenmann/go-kstat/doc.go  | 106 +++
 .../siebenmann/go-kstat/kstat-godoc.txt       | 455 ++++++++++++
 .../siebenmann/go-kstat/kstat_solaris.go      | 658 ++++++++++++++++++
 .../siebenmann/go-kstat/raw_solaris.go        | 236 +++++++
 .../go-kstat/types_solaris_amd64.go           | 141 ++++
 vendor/modules.txt                            |   2 +-
 26 files changed, 2200 insertions(+), 156 deletions(-)
 create mode 100644 vendor/github.com/prometheus/procfs/Makefile.common
 create mode 100644 vendor/github.com/prometheus/procfs/go.mod
 create mode 100644 vendor/github.com/prometheus/procfs/sysfs/class_thermal.go
 create mode 100644 vendor/github.com/siebenmann/go-kstat/.gitignore
 create mode 100644 vendor/github.com/siebenmann/go-kstat/Makefile
 create mode 100644 vendor/github.com/siebenmann/go-kstat/README
 create mode 100644 vendor/github.com/siebenmann/go-kstat/doc.go
 create mode 100644 vendor/github.com/siebenmann/go-kstat/kstat-godoc.txt
 create mode 100644 vendor/github.com/siebenmann/go-kstat/kstat_solaris.go
 create mode 100644 vendor/github.com/siebenmann/go-kstat/raw_solaris.go
 create mode 100644 vendor/github.com/siebenmann/go-kstat/types_solaris_amd64.go

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 86d380ad..28cefae4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,12 +2,15 @@
 
 ### **Breaking changes**
 
+The cpufreq metrics now separate the `cpufreq` and `scaling` data based on what the driver provides. #1248
+
 ### Changes
 
 * [BUGFIX]
 * [BUGFIX] Add fallback for missing /proc/1/mounts #1172
 * [CHANGE] Add TCPSynRetrans to netstat default filter #1143
 * [CHANGE] Add a limit to the number of in-flight requests #1166
+* [CHANGE] Add separate cpufreq and scaling metrics #1248
 * [ENHANCEMENT] Add Infiniband counters #1120
 * [FEATURE] Add a flag to disable exporter metrics #1148
 * [FEATURE] Add kstat-based Solaris metrics for boottime, cpu and zfs collectors #1197
diff --git a/collector/cpu_linux.go b/collector/cpu_linux.go
index 640873f4..50d8a3b1 100644
--- a/collector/cpu_linux.go
+++ b/collector/cpu_linux.go
@@ -32,6 +32,9 @@ type cpuCollector struct {
 	cpuFreq            *prometheus.Desc
 	cpuFreqMin         *prometheus.Desc
 	cpuFreqMax         *prometheus.Desc
+	scalingFreq        *prometheus.Desc
+	scalingFreqMin     *prometheus.Desc
+	scalingFreqMax     *prometheus.Desc
 	cpuCoreThrottle    *prometheus.Desc
 	cpuPackageThrottle *prometheus.Desc
 }
@@ -64,6 +67,21 @@ func NewCPUCollector() (Collector, error) {
 			"Maximum cpu thread frequency in hertz.",
 			[]string{"cpu"}, nil,
 		),
+		scalingFreq: prometheus.NewDesc(
+			prometheus.BuildFQName(namespace, cpuCollectorSubsystem, "scaling_frequency_hertz"),
+			"Current scaled cpu thread frequency in hertz.",
+			[]string{"cpu"}, nil,
+		),
+		scalingFreqMin: prometheus.NewDesc(
+			prometheus.BuildFQName(namespace, cpuCollectorSubsystem, "scaling_frequency_min_hrts"),
+			"Minimum scaled cpu thread frequency in hertz.",
+			[]string{"cpu"}, nil,
+		),
+		scalingFreqMax: prometheus.NewDesc(
+			prometheus.BuildFQName(namespace, cpuCollectorSubsystem, "scaling_frequency_max_hrts"),
+			"Maximum scaled cpu thread frequency in hertz.",
+			[]string{"cpu"}, nil,
+		),
 		cpuCoreThrottle: prometheus.NewDesc(
 			prometheus.BuildFQName(namespace, cpuCollectorSubsystem, "core_throttles_total"),
 			"Number of times this cpu core has been throttled.",
@@ -106,24 +124,54 @@ func (c *cpuCollector) updateCPUfreq(ch chan<- prometheus.Metric) error {
 	// sysfs cpufreq values are kHz, thus multiply by 1000 to export base units (hz).
 	// See https://www.kernel.org/doc/Documentation/cpu-freq/user-guide.txt
 	for _, stats := range cpuFreqs {
-		ch <- prometheus.MustNewConstMetric(
-			c.cpuFreq,
-			prometheus.GaugeValue,
-			float64(stats.CurrentFrequency)*1000.0,
-			stats.Name,
-		)
-		ch <- prometheus.MustNewConstMetric(
-			c.cpuFreqMin,
-			prometheus.GaugeValue,
-			float64(stats.MinimumFrequency)*1000.0,
-			stats.Name,
-		)
-		ch <- prometheus.MustNewConstMetric(
-			c.cpuFreqMax,
-			prometheus.GaugeValue,
-			float64(stats.MaximumFrequency)*1000.0,
-			stats.Name,
-		)
+		if stats.CpuinfoCurrentFrequency != nil {
+			ch <- prometheus.MustNewConstMetric(
+				c.cpuFreq,
+				prometheus.GaugeValue,
+				float64(*stats.CpuinfoCurrentFrequency)*1000.0,
+				stats.Name,
+			)
+		}
+		if stats.CpuinfoMinimumFrequency != nil {
+			ch <- prometheus.MustNewConstMetric(
+				c.cpuFreqMin,
+				prometheus.GaugeValue,
+				float64(*stats.CpuinfoMinimumFrequency)*1000.0,
+				stats.Name,
+			)
+		}
+		if stats.CpuinfoMaximumFrequency != nil {
+			ch <- prometheus.MustNewConstMetric(
+				c.cpuFreqMax,
+				prometheus.GaugeValue,
+				float64(*stats.CpuinfoMaximumFrequency)*1000.0,
+				stats.Name,
+			)
+		}
+		if stats.ScalingCurrentFrequency != nil {
+			ch <- prometheus.MustNewConstMetric(
+				c.scalingFreq,
+				prometheus.GaugeValue,
+				float64(*stats.ScalingCurrentFrequency)*1000.0,
+				stats.Name,
+			)
+		}
+		if stats.ScalingMinimumFrequency != nil {
+			ch <- prometheus.MustNewConstMetric(
+				c.scalingFreqMin,
+				prometheus.GaugeValue,
+				float64(*stats.ScalingMinimumFrequency)*1000.0,
+				stats.Name,
+			)
+		}
+		if stats.ScalingMaximumFrequency != nil {
+			ch <- prometheus.MustNewConstMetric(
+				c.scalingFreqMax,
+				prometheus.GaugeValue,
+				float64(*stats.ScalingMaximumFrequency)*1000.0,
+				stats.Name,
+			)
+		}
 	}
 	return nil
 }
diff --git a/collector/fixtures/e2e-64k-page-output.txt b/collector/fixtures/e2e-64k-page-output.txt
index feb6b37b..7e61462e 100644
--- a/collector/fixtures/e2e-64k-page-output.txt
+++ b/collector/fixtures/e2e-64k-page-output.txt
@@ -184,24 +184,6 @@ node_cpu_core_throttles_total{core="0",package="0"} 5
 node_cpu_core_throttles_total{core="0",package="1"} 0
 node_cpu_core_throttles_total{core="1",package="0"} 0
 node_cpu_core_throttles_total{core="1",package="1"} 9
-# HELP node_cpu_frequency_hertz Current cpu thread frequency in hertz.
-# TYPE node_cpu_frequency_hertz gauge
-node_cpu_frequency_hertz{cpu="0"} 1.699981e+09
-node_cpu_frequency_hertz{cpu="1"} 1.699981e+09
-node_cpu_frequency_hertz{cpu="2"} 8e+06
-node_cpu_frequency_hertz{cpu="3"} 8e+06
-# HELP node_cpu_frequency_max_hertz Maximum cpu thread frequency in hertz.
-# TYPE node_cpu_frequency_max_hertz gauge
-node_cpu_frequency_max_hertz{cpu="0"} 3.7e+09
-node_cpu_frequency_max_hertz{cpu="1"} 3.7e+09
-node_cpu_frequency_max_hertz{cpu="2"} 4.2e+09
-node_cpu_frequency_max_hertz{cpu="3"} 4.2e+09
-# HELP node_cpu_frequency_min_hertz Minimum cpu thread frequency in hertz.
-# TYPE node_cpu_frequency_min_hertz gauge
-node_cpu_frequency_min_hertz{cpu="0"} 8e+08
-node_cpu_frequency_min_hertz{cpu="1"} 8e+08
-node_cpu_frequency_min_hertz{cpu="2"} 1e+06
-node_cpu_frequency_min_hertz{cpu="3"} 1e+06
 # HELP node_cpu_guest_seconds_total Seconds the cpus spent in guests (VMs) for each mode.
 # TYPE node_cpu_guest_seconds_total counter
 node_cpu_guest_seconds_total{cpu="0",mode="nice"} 0.01
@@ -224,6 +206,24 @@ node_cpu_guest_seconds_total{cpu="7",mode="user"} 0.09
 # TYPE node_cpu_package_throttles_total counter
 node_cpu_package_throttles_total{package="0"} 30
 node_cpu_package_throttles_total{package="1"} 6
+# HELP node_cpu_scaling_frequency_hertz Current scaled cpu thread frequency in hertz.
+# TYPE node_cpu_scaling_frequency_hertz gauge
+node_cpu_scaling_frequency_hertz{cpu="0"} 1.699981e+09
+node_cpu_scaling_frequency_hertz{cpu="1"} 1.699981e+09
+node_cpu_scaling_frequency_hertz{cpu="2"} 8e+06
+node_cpu_scaling_frequency_hertz{cpu="3"} 8e+06
+# HELP node_cpu_scaling_frequency_max_hrts Maximum scaled cpu thread frequency in hertz.
+# TYPE node_cpu_scaling_frequency_max_hrts gauge
+node_cpu_scaling_frequency_max_hrts{cpu="0"} 3.7e+09
+node_cpu_scaling_frequency_max_hrts{cpu="1"} 3.7e+09
+node_cpu_scaling_frequency_max_hrts{cpu="2"} 4.2e+09
+node_cpu_scaling_frequency_max_hrts{cpu="3"} 4.2e+09
+# HELP node_cpu_scaling_frequency_min_hrts Minimum scaled cpu thread frequency in hertz.
+# TYPE node_cpu_scaling_frequency_min_hrts gauge
+node_cpu_scaling_frequency_min_hrts{cpu="0"} 8e+08
+node_cpu_scaling_frequency_min_hrts{cpu="1"} 8e+08
+node_cpu_scaling_frequency_min_hrts{cpu="2"} 1e+06
+node_cpu_scaling_frequency_min_hrts{cpu="3"} 1e+06
 # HELP node_cpu_seconds_total Seconds the cpus spent in each mode.
 # TYPE node_cpu_seconds_total counter
 node_cpu_seconds_total{cpu="0",mode="idle"} 10870.69
diff --git a/collector/fixtures/e2e-output.txt b/collector/fixtures/e2e-output.txt
index 588a5873..ba11e234 100644
--- a/collector/fixtures/e2e-output.txt
+++ b/collector/fixtures/e2e-output.txt
@@ -184,24 +184,6 @@ node_cpu_core_throttles_total{core="0",package="0"} 5
 node_cpu_core_throttles_total{core="0",package="1"} 0
 node_cpu_core_throttles_total{core="1",package="0"} 0
 node_cpu_core_throttles_total{core="1",package="1"} 9
-# HELP node_cpu_frequency_hertz Current cpu thread frequency in hertz.
-# TYPE node_cpu_frequency_hertz gauge
-node_cpu_frequency_hertz{cpu="0"} 1.699981e+09
-node_cpu_frequency_hertz{cpu="1"} 1.699981e+09
-node_cpu_frequency_hertz{cpu="2"} 8e+06
-node_cpu_frequency_hertz{cpu="3"} 8e+06
-# HELP node_cpu_frequency_max_hertz Maximum cpu thread frequency in hertz.
-# TYPE node_cpu_frequency_max_hertz gauge
-node_cpu_frequency_max_hertz{cpu="0"} 3.7e+09
-node_cpu_frequency_max_hertz{cpu="1"} 3.7e+09
-node_cpu_frequency_max_hertz{cpu="2"} 4.2e+09
-node_cpu_frequency_max_hertz{cpu="3"} 4.2e+09
-# HELP node_cpu_frequency_min_hertz Minimum cpu thread frequency in hertz.
-# TYPE node_cpu_frequency_min_hertz gauge
-node_cpu_frequency_min_hertz{cpu="0"} 8e+08
-node_cpu_frequency_min_hertz{cpu="1"} 8e+08
-node_cpu_frequency_min_hertz{cpu="2"} 1e+06
-node_cpu_frequency_min_hertz{cpu="3"} 1e+06
 # HELP node_cpu_guest_seconds_total Seconds the cpus spent in guests (VMs) for each mode.
 # TYPE node_cpu_guest_seconds_total counter
 node_cpu_guest_seconds_total{cpu="0",mode="nice"} 0.01
@@ -224,6 +206,24 @@ node_cpu_guest_seconds_total{cpu="7",mode="user"} 0.09
 # TYPE node_cpu_package_throttles_total counter
 node_cpu_package_throttles_total{package="0"} 30
 node_cpu_package_throttles_total{package="1"} 6
+# HELP node_cpu_scaling_frequency_hertz Current scaled cpu thread frequency in hertz.
+# TYPE node_cpu_scaling_frequency_hertz gauge
+node_cpu_scaling_frequency_hertz{cpu="0"} 1.699981e+09
+node_cpu_scaling_frequency_hertz{cpu="1"} 1.699981e+09
+node_cpu_scaling_frequency_hertz{cpu="2"} 8e+06
+node_cpu_scaling_frequency_hertz{cpu="3"} 8e+06
+# HELP node_cpu_scaling_frequency_max_hrts Maximum scaled cpu thread frequency in hertz.
+# TYPE node_cpu_scaling_frequency_max_hrts gauge
+node_cpu_scaling_frequency_max_hrts{cpu="0"} 3.7e+09
+node_cpu_scaling_frequency_max_hrts{cpu="1"} 3.7e+09
+node_cpu_scaling_frequency_max_hrts{cpu="2"} 4.2e+09
+node_cpu_scaling_frequency_max_hrts{cpu="3"} 4.2e+09
+# HELP node_cpu_scaling_frequency_min_hrts Minimum scaled cpu thread frequency in hertz.
+# TYPE node_cpu_scaling_frequency_min_hrts gauge
+node_cpu_scaling_frequency_min_hrts{cpu="0"} 8e+08
+node_cpu_scaling_frequency_min_hrts{cpu="1"} 8e+08
+node_cpu_scaling_frequency_min_hrts{cpu="2"} 1e+06
+node_cpu_scaling_frequency_min_hrts{cpu="3"} 1e+06
 # HELP node_cpu_seconds_total Seconds the cpus spent in each mode.
 # TYPE node_cpu_seconds_total counter
 node_cpu_seconds_total{cpu="0",mode="idle"} 10870.69
diff --git a/go.mod b/go.mod
index 8b80a617..c6ea6a6e 100644
--- a/go.mod
+++ b/go.mod
@@ -21,7 +21,7 @@ require (
 	github.com/prometheus/client_golang v0.9.1
 	github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910
 	github.com/prometheus/common v0.0.0-20181015124227-bcb74de08d37
-	github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d
+	github.com/prometheus/procfs v0.0.0-20190129233650-316cf8ccfec5
 	github.com/siebenmann/go-kstat v0.0.0-20160321171754-d34789b79745
 	github.com/sirupsen/logrus v1.1.1 // indirect
 	github.com/soundcloud/go-runit v0.0.0-20150630195641-06ad41a06c4a
diff --git a/go.sum b/go.sum
index 8fec81b2..235249cf 100644
--- a/go.sum
+++ b/go.sum
@@ -43,8 +43,8 @@ github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/common v0.0.0-20181015124227-bcb74de08d37 h1:Y7YdJ9Xb3MoQOzAWXnDunAJYpvhVwZdTirNfGUgPKaA=
 github.com/prometheus/common v0.0.0-20181015124227-bcb74de08d37/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
-github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d h1:GoAlyOgbOEIFdaDqxJVlbOQ1DtGmZWs/Qau0hIlk+WQ=
-github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190129233650-316cf8ccfec5 h1:Etei0Wx6pooT/DeOKcGTr1M/01ggz95Ajq8BBwCOKBU=
+github.com/prometheus/procfs v0.0.0-20190129233650-316cf8ccfec5/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
 github.com/siebenmann/go-kstat v0.0.0-20160321171754-d34789b79745 h1:IuH7WumZNax0D+rEqmy2TyhKCzrtMGqbZO0b8rO00JA=
 github.com/siebenmann/go-kstat v0.0.0-20160321171754-d34789b79745/go.mod h1:G81aIFAMS9ECrwBYR9YxhlPjWgrItd+Kje78O6+uqm8=
 github.com/sirupsen/logrus v1.1.1 h1:VzGj7lhU7KEB9e9gMpAV/v5XT2NVSvLJhJLCWbnkgXg=
diff --git a/vendor/github.com/prometheus/procfs/MAINTAINERS.md b/vendor/github.com/prometheus/procfs/MAINTAINERS.md
index 35993c41..f1d3b993 100644
--- a/vendor/github.com/prometheus/procfs/MAINTAINERS.md
+++ b/vendor/github.com/prometheus/procfs/MAINTAINERS.md
@@ -1 +1,2 @@
-* Tobias Schmidt <tobidt@gmail.com>
+* Tobias Schmidt <tobidt@gmail.com> @grobie
+* Johannes 'fish' Ziemke <github@freigeist.org> @discordianfish
diff --git a/vendor/github.com/prometheus/procfs/Makefile b/vendor/github.com/prometheus/procfs/Makefile
index 4d109839..947d7d8f 100644
--- a/vendor/github.com/prometheus/procfs/Makefile
+++ b/vendor/github.com/prometheus/procfs/Makefile
@@ -11,49 +11,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Ensure GOBIN is not set during build so that promu is installed to the correct path
-unexport GOBIN
-
-GO           ?= go
-GOFMT        ?= $(GO)fmt
-FIRST_GOPATH := $(firstword $(subst :, ,$(shell $(GO) env GOPATH)))
-STATICCHECK  := $(FIRST_GOPATH)/bin/staticcheck
-pkgs          = $(shell $(GO) list ./... | grep -v /vendor/)
-
-PREFIX                  ?= $(shell pwd)
-BIN_DIR                 ?= $(shell pwd)
-
-ifdef DEBUG
-  bindata_flags = -debug
-endif
-
-STATICCHECK_IGNORE =
-
-all: format staticcheck build test
-
-style:
-	@echo ">> checking code style"
-	@! $(GOFMT) -d $(shell find . -path ./vendor -prune -o -name '*.go' -print) | grep '^'
-
-check_license:
-	@echo ">> checking license header"
-	@./scripts/check_license.sh
-
-test: fixtures/.unpacked sysfs/fixtures/.unpacked
-	@echo ">> running all tests"
-	@$(GO) test -race $(shell $(GO) list ./... | grep -v /vendor/ | grep -v examples)
-
-format:
-	@echo ">> formatting code"
-	@$(GO) fmt $(pkgs)
-
-vet:
-	@echo ">> vetting code"
-	@$(GO) vet $(pkgs)
-
-staticcheck: $(STATICCHECK)
-	@echo ">> running staticcheck"
-	@$(STATICCHECK) -ignore "$(STATICCHECK_IGNORE)" $(pkgs)
+include Makefile.common
 
 %/.unpacked: %.ttar
 	./ttar -C $(dir $*) -x -f $*.ttar
@@ -65,13 +23,8 @@ update_fixtures: fixtures.ttar sysfs/fixtures.ttar
 	rm -v $(dir $*)fixtures/.unpacked
 	./ttar -C $(dir $*) -c -f $*fixtures.ttar fixtures/
 
-$(FIRST_GOPATH)/bin/staticcheck:
-	@GOOS= GOARCH= $(GO) get -u honnef.co/go/tools/cmd/staticcheck
+.PHONY: build
+build:
 
-.PHONY: all style check_license format test vet staticcheck
-
-# Declaring the binaries at their default locations as PHONY targets is a hack
-# to ensure the latest version is downloaded on every make execution.
-# If this is not desired, copy/symlink these binaries to a different path and
-# set the respective environment variables.
-.PHONY: $(GOPATH)/bin/staticcheck
+.PHONY: test
+test: fixtures/.unpacked sysfs/fixtures/.unpacked common-test
diff --git a/vendor/github.com/prometheus/procfs/Makefile.common b/vendor/github.com/prometheus/procfs/Makefile.common
new file mode 100644
index 00000000..741579e6
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/Makefile.common
@@ -0,0 +1,223 @@
+# Copyright 2018 The Prometheus Authors
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+# A common Makefile that includes rules to be reused in different prometheus projects.
+# !!! Open PRs only against the prometheus/prometheus/Makefile.common repository!
+
+# Example usage :
+# Create the main Makefile in the root project directory.
+# include Makefile.common
+# customTarget:
+# 	@echo ">> Running customTarget"
+#
+
+# Ensure GOBIN is not set during build so that promu is installed to the correct path
+unexport GOBIN
+
+GO           ?= go
+GOFMT        ?= $(GO)fmt
+FIRST_GOPATH := $(firstword $(subst :, ,$(shell $(GO) env GOPATH)))
+GOOPTS       ?=
+
+GO_VERSION        ?= $(shell $(GO) version)
+GO_VERSION_NUMBER ?= $(word 3, $(GO_VERSION))
+PRE_GO_111        ?= $(shell echo $(GO_VERSION_NUMBER) | grep -E 'go1\.(10|[0-9])\.')
+
+unexport GOVENDOR
+ifeq (, $(PRE_GO_111))
+	ifneq (,$(wildcard go.mod))
+		# Enforce Go modules support just in case the directory is inside GOPATH (and for Travis CI).
+		GO111MODULE := on
+
+		ifneq (,$(wildcard vendor))
+			# Always use the local vendor/ directory to satisfy the dependencies.
+			GOOPTS := $(GOOPTS) -mod=vendor
+		endif
+	endif
+else
+	ifneq (,$(wildcard go.mod))
+		ifneq (,$(wildcard vendor))
+$(warning This repository requires Go >= 1.11 because of Go modules)
+$(warning Some recipes may not work as expected as the current Go runtime is '$(GO_VERSION_NUMBER)')
+		endif
+	else
+		# This repository isn't using Go modules (yet).
+		GOVENDOR := $(FIRST_GOPATH)/bin/govendor
+	endif
+
+	unexport GO111MODULE
+endif
+PROMU        := $(FIRST_GOPATH)/bin/promu
+STATICCHECK  := $(FIRST_GOPATH)/bin/staticcheck
+pkgs          = ./...
+
+GO_VERSION        ?= $(shell $(GO) version)
+GO_BUILD_PLATFORM ?= $(subst /,-,$(lastword $(GO_VERSION)))
+
+PROMU_VERSION ?= 0.2.0
+PROMU_URL     := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz
+
+PREFIX                  ?= $(shell pwd)
+BIN_DIR                 ?= $(shell pwd)
+DOCKER_IMAGE_TAG        ?= $(subst /,-,$(shell git rev-parse --abbrev-ref HEAD))
+DOCKER_REPO             ?= prom
+
+.PHONY: all
+all: precheck style staticcheck unused build test
+
+# This rule is used to forward a target like "build" to "common-build".  This
+# allows a new "build" target to be defined in a Makefile which includes this
+# one and override "common-build" without override warnings.
+%: common-% ;
+
+.PHONY: common-style
+common-style:
+	@echo ">> checking code style"
+	@fmtRes=$$($(GOFMT) -d $$(find . -path ./vendor -prune -o -name '*.go' -print)); \
+	if [ -n "$${fmtRes}" ]; then \
+		echo "gofmt checking failed!"; echo "$${fmtRes}"; echo; \
+		echo "Please ensure you are using $$($(GO) version) for formatting code."; \
+		exit 1; \
+	fi
+
+.PHONY: common-check_license
+common-check_license:
+	@echo ">> checking license header"
+	@licRes=$$(for file in $$(find . -type f -iname '*.go' ! -path './vendor/*') ; do \
+               awk 'NR<=3' $$file | grep -Eq "(Copyright|generated|GENERATED)" || echo $$file; \
+       done); \
+       if [ -n "$${licRes}" ]; then \
+               echo "license header checking failed:"; echo "$${licRes}"; \
+               exit 1; \
+       fi
+
+.PHONY: common-test-short
+common-test-short:
+	@echo ">> running short tests"
+	GO111MODULE=$(GO111MODULE) $(GO) test -short $(GOOPTS) $(pkgs)
+
+.PHONY: common-test
+common-test:
+	@echo ">> running all tests"
+	GO111MODULE=$(GO111MODULE) $(GO) test -race $(GOOPTS) $(pkgs)
+
+.PHONY: common-format
+common-format:
+	@echo ">> formatting code"
+	GO111MODULE=$(GO111MODULE) $(GO) fmt $(GOOPTS) $(pkgs)
+
+.PHONY: common-vet
+common-vet:
+	@echo ">> vetting code"
+	GO111MODULE=$(GO111MODULE) $(GO) vet $(GOOPTS) $(pkgs)
+
+.PHONY: common-staticcheck
+common-staticcheck: $(STATICCHECK)
+	@echo ">> running staticcheck"
+ifdef GO111MODULE
+	GO111MODULE=$(GO111MODULE) $(STATICCHECK) -ignore "$(STATICCHECK_IGNORE)" -checks "SA*" $(pkgs)
+else
+	$(STATICCHECK) -ignore "$(STATICCHECK_IGNORE)" $(pkgs)
+endif
+
+.PHONY: common-unused
+common-unused: $(GOVENDOR)
+ifdef GOVENDOR
+	@echo ">> running check for unused packages"
+	@$(GOVENDOR) list +unused | grep . && exit 1 || echo 'No unused packages'
+else
+ifdef GO111MODULE
+	@echo ">> running check for unused/missing packages in go.mod"
+	GO111MODULE=$(GO111MODULE) $(GO) mod tidy
+	@git diff --exit-code -- go.sum go.mod
+ifneq (,$(wildcard vendor))
+	@echo ">> running check for unused packages in vendor/"
+	GO111MODULE=$(GO111MODULE) $(GO) mod vendor
+	@git diff --exit-code -- go.sum go.mod vendor/
+endif
+endif
+endif
+
+.PHONY: common-build
+common-build: promu
+	@echo ">> building binaries"
+	GO111MODULE=$(GO111MODULE) $(PROMU) build --prefix $(PREFIX)
+
+.PHONY: common-tarball
+common-tarball: promu
+	@echo ">> building release tarball"
+	$(PROMU) tarball --prefix $(PREFIX) $(BIN_DIR)
+
+.PHONY: common-docker
+common-docker:
+	docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" .
+
+.PHONY: common-docker-publish
+common-docker-publish:
+	docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)"
+
+.PHONY: common-docker-tag-latest
+common-docker-tag-latest:
+	docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):latest"
+
+.PHONY: promu
+promu: $(PROMU)
+
+$(PROMU):
+	curl -s -L $(PROMU_URL) | tar -xvz -C /tmp
+	mkdir -v -p $(FIRST_GOPATH)/bin
+	cp -v /tmp/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM)/promu $(PROMU)
+
+.PHONY: proto
+proto:
+	@echo ">> generating code from proto files"
+	@./scripts/genproto.sh
+
+.PHONY: $(STATICCHECK)
+$(STATICCHECK):
+ifdef GO111MODULE
+# Get staticcheck from a temporary directory to avoid modifying the local go.{mod,sum}.
+# See https://github.com/golang/go/issues/27643.
+# For now, we are using the next branch of staticcheck because master isn't compatible yet with Go modules.
+	tmpModule=$$(mktemp -d 2>&1) && \
+	mkdir -p $${tmpModule}/staticcheck && \
+	cd "$${tmpModule}"/staticcheck && \
+	GO111MODULE=on $(GO) mod init example.com/staticcheck && \
+	GO111MODULE=on GOOS= GOARCH= $(GO) get -u honnef.co/go/tools/cmd/staticcheck@next && \
+	rm -rf $${tmpModule};
+else
+	GOOS= GOARCH= GO111MODULE=off $(GO) get -u honnef.co/go/tools/cmd/staticcheck
+endif
+
+ifdef GOVENDOR
+.PHONY: $(GOVENDOR)
+$(GOVENDOR):
+	GOOS= GOARCH= $(GO) get -u github.com/kardianos/govendor
+endif
+
+.PHONY: precheck
+precheck::
+
+define PRECHECK_COMMAND_template =
+precheck:: $(1)_precheck
+
+
+PRECHECK_COMMAND_$(1) ?= $(1) $$(strip $$(PRECHECK_OPTIONS_$(1)))
+.PHONY: $(1)_precheck
+$(1)_precheck:
+	@if ! $$(PRECHECK_COMMAND_$(1)) 1>/dev/null 2>&1; then \
+		echo "Execution of '$$(PRECHECK_COMMAND_$(1))' command failed. Is $(1) installed?"; \
+		exit 1; \
+	fi
+endef
diff --git a/vendor/github.com/prometheus/procfs/go.mod b/vendor/github.com/prometheus/procfs/go.mod
new file mode 100644
index 00000000..e89ee6c9
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/go.mod
@@ -0,0 +1 @@
+module github.com/prometheus/procfs
diff --git a/vendor/github.com/prometheus/procfs/internal/util/parse.go b/vendor/github.com/prometheus/procfs/internal/util/parse.go
index 2ff228e9..ca74889a 100644
--- a/vendor/github.com/prometheus/procfs/internal/util/parse.go
+++ b/vendor/github.com/prometheus/procfs/internal/util/parse.go
@@ -57,3 +57,17 @@ func ReadUintFromFile(path string) (uint64, error) {
 	}
 	return strconv.ParseUint(strings.TrimSpace(string(data)), 10, 64)
 }
+
+// ParseBool parses a string into a boolean pointer.
+func ParseBool(b string) *bool {
+	var truth bool
+	switch b {
+	case "enabled":
+		truth = true
+	case "disabled":
+		truth = false
+	default:
+		return nil
+	}
+	return &truth
+}
diff --git a/vendor/github.com/prometheus/procfs/mountstats.go b/vendor/github.com/prometheus/procfs/mountstats.go
index 7a8a1e09..fc385afc 100644
--- a/vendor/github.com/prometheus/procfs/mountstats.go
+++ b/vendor/github.com/prometheus/procfs/mountstats.go
@@ -69,6 +69,8 @@ type MountStats interface {
 type MountStatsNFS struct {
 	// The version of statistics provided.
 	StatVersion string
+	// The optional mountaddr of the NFS mount.
+	MountAddress string
 	// The age of the NFS mount.
 	Age time.Duration
 	// Statistics related to byte counters for various operations.
@@ -317,6 +319,7 @@ func parseMount(ss []string) (*Mount, error) {
 func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, error) {
 	// Field indicators for parsing specific types of data
 	const (
+		fieldOpts       = "opts:"
 		fieldAge        = "age:"
 		fieldBytes      = "bytes:"
 		fieldEvents     = "events:"
@@ -338,6 +341,13 @@ func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, e
 		}
 
 		switch ss[0] {
+		case fieldOpts:
+			for _, opt := range strings.Split(ss[1], ",") {
+				split := strings.Split(opt, "=")
+				if len(split) == 2 && split[0] == "mountaddr" {
+					stats.MountAddress = split[1]
+				}
+			}
 		case fieldAge:
 			// Age integer is in seconds
 			d, err := time.ParseDuration(ss[1] + "s")
diff --git a/vendor/github.com/prometheus/procfs/proc_stat.go b/vendor/github.com/prometheus/procfs/proc_stat.go
index 3cf2a9f1..e7c626a8 100644
--- a/vendor/github.com/prometheus/procfs/proc_stat.go
+++ b/vendor/github.com/prometheus/procfs/proc_stat.go
@@ -95,7 +95,7 @@ type ProcStat struct {
 	// in clock ticks.
 	Starttime uint64
 	// Virtual memory size in bytes.
-	VSize int
+	VSize uint
 	// Resident set size in pages.
 	RSS int
 
@@ -164,7 +164,7 @@ func (p Proc) NewStat() (ProcStat, error) {
 }
 
 // VirtualMemory returns the virtual memory size in bytes.
-func (s ProcStat) VirtualMemory() int {
+func (s ProcStat) VirtualMemory() uint {
 	return s.VSize
 }
 
diff --git a/vendor/github.com/prometheus/procfs/sysfs/class_thermal.go b/vendor/github.com/prometheus/procfs/sysfs/class_thermal.go
new file mode 100644
index 00000000..4f9cb9a1
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/sysfs/class_thermal.go
@@ -0,0 +1,99 @@
+// Copyright 2018 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// +build !windows
+
+package sysfs
+
+import (
+	"os"
+	"path/filepath"
+	"strings"
+
+	"github.com/prometheus/procfs/internal/util"
+)
+
+// ClassThermalZoneStats contains info from files in /sys/class/thermal/thermal_zone<zone>
+// for a single <zone>.
+// https://www.kernel.org/doc/Documentation/thermal/sysfs-api.txt
+type ClassThermalZoneStats struct {
+	Name    string  // The name of the zone from the directory structure.
+	Type    string  // The type of thermal zone.
+	Temp    uint64  // Temperature in millidegree Celsius.
+	Policy  string  // One of the various thermal governors used for a particular zone.
+	Mode    *bool   // Optional: One of the predefined values in [enabled, disabled].
+	Passive *uint64 // Optional: millidegrees Celsius. (0 for disabled, > 1000 for enabled+value)
+}
+
+// NewClassThermalZoneStats returns Thermal Zone metrics for all zones.
+func (fs FS) NewClassThermalZoneStats() ([]ClassThermalZoneStats, error) {
+	zones, err := filepath.Glob(fs.Path("class/thermal/thermal_zone[0-9]*"))
+	if err != nil {
+		return []ClassThermalZoneStats{}, err
+	}
+
+	var zoneStats = ClassThermalZoneStats{}
+	stats := make([]ClassThermalZoneStats, len(zones))
+	for i, zone := range zones {
+		zoneName := strings.TrimPrefix(filepath.Base(zone), "thermal_zone")
+
+		zoneStats, err = parseClassThermalZone(zone)
+		if err != nil {
+			return []ClassThermalZoneStats{}, err
+		}
+		zoneStats.Name = zoneName
+		stats[i] = zoneStats
+	}
+	return stats, nil
+}
+
+func parseClassThermalZone(zone string) (ClassThermalZoneStats, error) {
+	// Required attributes.
+	zoneType, err := util.SysReadFile(filepath.Join(zone, "type"))
+	if err != nil {
+		return ClassThermalZoneStats{}, err
+	}
+	zonePolicy, err := util.SysReadFile(filepath.Join(zone, "policy"))
+	if err != nil {
+		return ClassThermalZoneStats{}, err
+	}
+	zoneTemp, err := util.ReadUintFromFile(filepath.Join(zone, "temp"))
+	if err != nil {
+		return ClassThermalZoneStats{}, err
+	}
+
+	// Optional attributes.
+	mode, err := util.SysReadFile(filepath.Join(zone, "mode"))
+	if err != nil && !os.IsNotExist(err) && !os.IsPermission(err) {
+		return ClassThermalZoneStats{}, err
+	}
+	zoneMode := util.ParseBool(mode)
+
+	var zonePassive *uint64
+	passive, err := util.ReadUintFromFile(filepath.Join(zone, "passive"))
+	if os.IsNotExist(err) || os.IsPermission(err) {
+		zonePassive = nil
+	} else if err != nil {
+		return ClassThermalZoneStats{}, err
+	} else {
+		zonePassive = &passive
+	}
+
+	return ClassThermalZoneStats{
+		Type:    zoneType,
+		Policy:  zonePolicy,
+		Temp:    zoneTemp,
+		Mode:    zoneMode,
+		Passive: zonePassive,
+	}, nil
+}
diff --git a/vendor/github.com/prometheus/procfs/sysfs/fixtures.ttar b/vendor/github.com/prometheus/procfs/sysfs/fixtures.ttar
index c0ac683e..33bdbdb8 100644
--- a/vendor/github.com/prometheus/procfs/sysfs/fixtures.ttar
+++ b/vendor/github.com/prometheus/procfs/sysfs/fixtures.ttar
@@ -137,6 +137,55 @@ Lines: 1
 1
 Mode: 644
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/class/thermal
+Mode: 775
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/class/thermal/thermal_zone0
+Mode: 775
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/class/thermal/thermal_zone0/policy
+Lines: 1
+step_wise
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/class/thermal/thermal_zone0/temp
+Lines: 1
+49925
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/class/thermal/thermal_zone0/type
+Lines: 1
+bcm2835_thermal
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/class/thermal/thermal_zone1
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/class/thermal/thermal_zone1/mode
+Lines: 1
+enabled
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/class/thermal/thermal_zone1/passive
+Lines: 1
+0
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/class/thermal/thermal_zone1/policy
+Lines: 1
+step_wise
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/class/thermal/thermal_zone1/temp
+Lines: 1
+44000
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/class/thermal/thermal_zone1/type
+Lines: 1
+acpitz
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 Directory: fixtures/devices
 Mode: 755
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/vendor/github.com/prometheus/procfs/sysfs/system_cpu.go b/vendor/github.com/prometheus/procfs/sysfs/system_cpu.go
index c90f569c..3ea56d05 100644
--- a/vendor/github.com/prometheus/procfs/sysfs/system_cpu.go
+++ b/vendor/github.com/prometheus/procfs/sysfs/system_cpu.go
@@ -16,7 +16,6 @@
 package sysfs
 
 import (
-	"fmt"
 	"os"
 	"path/filepath"
 	"strings"
@@ -26,16 +25,19 @@ import (
 
 // SystemCPUCpufreqStats contains stats from devices/system/cpu/cpu[0-9]*/cpufreq/...
 type SystemCPUCpufreqStats struct {
-	Name               string
-	CurrentFrequency   uint64
-	MinimumFrequency   uint64
-	MaximumFrequency   uint64
-	TransitionLatency  uint64
-	AvailableGovernors string
-	Driver             string
-	Govenor            string
-	RelatedCpus        string
-	SetSpeed           string
+	Name                     string
+	CpuinfoCurrentFrequency  *uint64
+	CpuinfoMinimumFrequency  *uint64
+	CpuinfoMaximumFrequency  *uint64
+	CpuinfoTransitionLatency *uint64
+	ScalingCurrentFrequency  *uint64
+	ScalingMinimumFrequency  *uint64
+	ScalingMaximumFrequency  *uint64
+	AvailableGovernors       string
+	Driver                   string
+	Govenor                  string
+	RelatedCpus              string
+	SetSpeed                 string
 }
 
 // TODO: Add topology support.
@@ -74,14 +76,7 @@ func (fs FS) NewSystemCpufreq() ([]SystemCPUCpufreqStats, error) {
 			return []SystemCPUCpufreqStats{}, err
 		}
 
-		if _, err = os.Stat(filepath.Join(cpuCpufreqPath, "scaling_cur_freq")); err == nil {
-			cpufreq, err = parseCpufreqCpuinfo("scaling", cpuCpufreqPath)
-		} else if _, err = os.Stat(filepath.Join(cpuCpufreqPath, "cpuinfo_cur_freq")); err == nil {
-			// Older kernels have metrics named `cpuinfo_...`.
-			cpufreq, err = parseCpufreqCpuinfo("cpuinfo", cpuCpufreqPath)
-		} else {
-			return []SystemCPUCpufreqStats{}, fmt.Errorf("CPU %v is missing cpufreq", cpu)
-		}
+		cpufreq, err = parseCpufreqCpuinfo(cpuCpufreqPath)
 		if err != nil {
 			return []SystemCPUCpufreqStats{}, err
 		}
@@ -92,22 +87,28 @@ func (fs FS) NewSystemCpufreq() ([]SystemCPUCpufreqStats, error) {
 	return systemCpufreq, nil
 }
 
-func parseCpufreqCpuinfo(prefix string, cpuPath string) (*SystemCPUCpufreqStats, error) {
+func parseCpufreqCpuinfo(cpuPath string) (*SystemCPUCpufreqStats, error) {
 	uintFiles := []string{
-		prefix + "_cur_freq",
-		prefix + "_max_freq",
-		prefix + "_min_freq",
+		"cpuinfo_cur_freq",
+		"cpuinfo_max_freq",
+		"cpuinfo_min_freq",
 		"cpuinfo_transition_latency",
+		"scaling_cur_freq",
+		"scaling_max_freq",
+		"scaling_min_freq",
 	}
-	uintOut := make([]uint64, len(uintFiles))
+	uintOut := make([]*uint64, len(uintFiles))
 
 	for i, f := range uintFiles {
 		v, err := util.ReadUintFromFile(filepath.Join(cpuPath, f))
 		if err != nil {
+			if os.IsNotExist(err) || os.IsPermission(err) {
+				continue
+			}
 			return &SystemCPUCpufreqStats{}, err
 		}
 
-		uintOut[i] = v
+		uintOut[i] = &v
 	}
 
 	stringFiles := []string{
@@ -128,14 +129,17 @@ func parseCpufreqCpuinfo(prefix string, cpuPath string) (*SystemCPUCpufreqStats,
 	}
 
 	return &SystemCPUCpufreqStats{
-		CurrentFrequency:   uintOut[0],
-		MaximumFrequency:   uintOut[1],
-		MinimumFrequency:   uintOut[2],
-		TransitionLatency:  uintOut[3],
-		AvailableGovernors: stringOut[0],
-		Driver:             stringOut[1],
-		Govenor:            stringOut[2],
-		RelatedCpus:        stringOut[3],
-		SetSpeed:           stringOut[4],
+		CpuinfoCurrentFrequency:  uintOut[0],
+		CpuinfoMaximumFrequency:  uintOut[1],
+		CpuinfoMinimumFrequency:  uintOut[2],
+		CpuinfoTransitionLatency: uintOut[3],
+		ScalingCurrentFrequency:  uintOut[4],
+		ScalingMaximumFrequency:  uintOut[5],
+		ScalingMinimumFrequency:  uintOut[6],
+		AvailableGovernors:       stringOut[0],
+		Driver:                   stringOut[1],
+		Govenor:                  stringOut[2],
+		RelatedCpus:              stringOut[3],
+		SetSpeed:                 stringOut[4],
 	}, nil
 }
diff --git a/vendor/github.com/prometheus/procfs/xfs/parse.go b/vendor/github.com/prometheus/procfs/xfs/parse.go
index 2bc0ef34..b3d8634d 100644
--- a/vendor/github.com/prometheus/procfs/xfs/parse.go
+++ b/vendor/github.com/prometheus/procfs/xfs/parse.go
@@ -43,15 +43,15 @@ func ParseStats(r io.Reader) (*Stats, error) {
 		fieldXpc         = "xpc"
 
 		// Unimplemented at this time due to lack of documentation.
-		fieldPushAil = "push_ail"
-		fieldXstrat  = "xstrat"
-		fieldAbtb2   = "abtb2"
-		fieldAbtc2   = "abtc2"
-		fieldBmbt2   = "bmbt2"
-		fieldIbt2    = "ibt2"
-		fieldFibt2   = "fibt2"
-		fieldQm      = "qm"
-		fieldDebug   = "debug"
+		// fieldPushAil = "push_ail"
+		// fieldXstrat  = "xstrat"
+		// fieldAbtb2   = "abtb2"
+		// fieldAbtc2   = "abtc2"
+		// fieldBmbt2   = "bmbt2"
+		// fieldIbt2    = "ibt2"
+		// fieldFibt2   = "fibt2"
+		// fieldQm      = "qm"
+		// fieldDebug   = "debug"
 	)
 
 	var xfss Stats
diff --git a/vendor/github.com/siebenmann/go-kstat/.gitignore b/vendor/github.com/siebenmann/go-kstat/.gitignore
new file mode 100644
index 00000000..b25c15b8
--- /dev/null
+++ b/vendor/github.com/siebenmann/go-kstat/.gitignore
@@ -0,0 +1 @@
+*~
diff --git a/vendor/github.com/siebenmann/go-kstat/Makefile b/vendor/github.com/siebenmann/go-kstat/Makefile
new file mode 100644
index 00000000..8e9c2356
--- /dev/null
+++ b/vendor/github.com/siebenmann/go-kstat/Makefile
@@ -0,0 +1,5 @@
+all:
+	@echo "Use 'make doctext' on a Solaris/Illumos/etc machine"
+
+doctext:
+	godoc github.com/siebenmann/go-kstat >kstat-godoc.txt
diff --git a/vendor/github.com/siebenmann/go-kstat/README b/vendor/github.com/siebenmann/go-kstat/README
new file mode 100644
index 00000000..07bfb71e
--- /dev/null
+++ b/vendor/github.com/siebenmann/go-kstat/README
@@ -0,0 +1,37 @@
+Go-kstat provides a Go API for the kstat kernel statistics system
+on Solaris, Illumos, OmniOS, and other Solaris derived systems. For
+general information on kstats, see the kstat(1) and kstat(3kstat)
+manpages. For more documentation on the details of the package, see
+doc.go, kstat_solaris.go, types_solaris_amd64.go, and raw_solaris.go.
+
+This package is quite young, so the API may well change as I and
+other people gain experience with using it.
+
+The API supports access to 'named' kstat statistics, IO statistics,
+and the most common and useful sorts of 'raw' kstat statistics
+(unix:0:sysinfo, unix:0:vminfo, unix:0:var, and mnt:*:mntinfo).
+Other raw kstat statistics are not explicitly supported, but the
+API provides some escape hatches for access to custom raw
+statistics.
+
+This is a cgo-based package so it can't be cross compiled like a regular
+Go package. It may also have bugs with memory management, since it
+interacts with the Solaris kstat library and holds references to memory
+that's been dynamically allocated in C.
+
+See kstat-godoc.txt for a text dump of the full godoc for the package.
+Unfortunately Go tool limitations appear to make it impossible to see
+full package documentat on anything except a Solaris machine (including
+https://godoc.org/, sadly).
+
+Bug reports and other contributions are highly welcome.
+
+Author:
+
+Chris Siebenmann
+https://github.com/siebenmann/go-kstat
+https://utcc.utoronto.ca/~cks/space/blog/
+
+(and elsewhere)
+
+Copyright: standard Go copyright
diff --git a/vendor/github.com/siebenmann/go-kstat/doc.go b/vendor/github.com/siebenmann/go-kstat/doc.go
new file mode 100644
index 00000000..5dce79dc
--- /dev/null
+++ b/vendor/github.com/siebenmann/go-kstat/doc.go
@@ -0,0 +1,106 @@
+//
+// 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.
+//
+// PERFORMANCE
+//
+// 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).
+//
+// SUPPORTED AND UNSUPPORTED KSTAT TYPES
+//
+// 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:
+//
+// https://utcc.utoronto.ca/~cks/space/blog/programming/GoCGoCompatibleStructs
+//
+// Author: Chris Siebenmann
+// https://github.com/siebenmann/go-kstat
+//
+// 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.)
+//
+package kstat
+
+//
+// This exists in large part to give non-Solaris systems something
+// that makes the package name visible. Otherwise eg goimports thinks
+// that this is an empty package and deletes 'import ...' statements
+// for it if you process a Go file that imports the package on a
+// non-Solaris platform.
+//
+// Since this file exists, I've put the package-level documentation
+// here to increase the odds that tools running on non-Solaris systems
+// will be able to show you at least some documentation.
+//
+// This is a hack, and annoying.
diff --git a/vendor/github.com/siebenmann/go-kstat/kstat-godoc.txt b/vendor/github.com/siebenmann/go-kstat/kstat-godoc.txt
new file mode 100644
index 00000000..d848406c
--- /dev/null
+++ b/vendor/github.com/siebenmann/go-kstat/kstat-godoc.txt
@@ -0,0 +1,455 @@
+PACKAGE DOCUMENTATION
+
+package kstat
+    import "github.com/siebenmann/go-kstat"
+
+    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.
+
+
+    PERFORMANCE
+
+    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).
+
+
+    SUPPORTED AND UNSUPPORTED KSTAT TYPES
+
+    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:
+
+    https://utcc.utoronto.ca/~cks/space/blog/programming/GoCGoCompatibleStructs
+
+    Author: Chris Siebenmann https://github.com/siebenmann/go-kstat
+
+    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.)
+
+FUNCTIONS
+
+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.)
+
+TYPES
+
+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 (
+    RawStat   KSType = C.KSTAT_TYPE_RAW
+    NamedStat KSType = C.KSTAT_TYPE_NAMED
+    IntrStat  KSType = C.KSTAT_TYPE_INTR
+    IoStat    KSType = C.KSTAT_TYPE_IO
+    TimerStat KSType = C.KSTAT_TYPE_TIMER
+)
+    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
+    statistics.
+
+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
+    data.
+
+    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
+
+	module:instance:name:statistic
+
+    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
+    statistic.
+
+    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.
+
+SUBDIRECTORIES
+
+	cmd
+	gen
+
diff --git a/vendor/github.com/siebenmann/go-kstat/kstat_solaris.go b/vendor/github.com/siebenmann/go-kstat/kstat_solaris.go
new file mode 100644
index 00000000..55dac116
--- /dev/null
+++ b/vendor/github.com/siebenmann/go-kstat/kstat_solaris.go
@@ -0,0 +1,658 @@
+//
+// The kstat package 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).
+//
+// In an ideal world the package documentation would go here. This is
+// not an ideal world, because any number of tools like godoc choke on
+// Go files that are not for their architecture (although I'll admit
+// it's a hard problem). So see doc.go for the actual package level
+// documentation.
+//
+// However, I refuse to push function level API documentation off to another
+// file, at least at the moment. It would be a horrible mess.
+//
+
+package kstat
+
+// #cgo LDFLAGS: -lkstat
+//
+// #include <sys/types.h>
+// #include <stdlib.h>
+// #include <strings.h>
+// #include <kstat.h>
+//
+// /* We have to reach through unions, which cgo doesn't support.
+//    So we have our own cheesy little routines for it. These assume
+//    they are always being called on validly-typed named kstats.
+//  */
+//
+// char *get_named_char(kstat_named_t *knp) {
+//	return knp->value.str.addr.ptr;
+// }
+//
+// uint64_t get_named_uint(kstat_named_t *knp) {
+//	if (knp->data_type == KSTAT_DATA_UINT32)
+//		return knp->value.ui32;
+//	else
+//		return knp->value.ui64;
+// }
+//
+// int64_t get_named_int(kstat_named_t *knp) {
+//	if (knp->data_type == KSTAT_DATA_INT32)
+//		return knp->value.i32;
+//	else
+//		return knp->value.i64;
+// }
+//
+// /* Let's not try to do C pointer arithmetic in Go and get it wrong */
+// kstat_named_t *get_nth_named(kstat_t *ks, uint_t n) {
+//	kstat_named_t *knp;
+//	if (!ks || !ks->ks_data || ks->ks_type != KSTAT_TYPE_NAMED || n >= ks->ks_ndata)
+//		return NULL;
+//	knp = KSTAT_NAMED_PTR(ks);
+//	return knp + n;
+// }
+//
+import "C"
+
+import (
+	"errors"
+	"fmt"
+	"runtime"
+	"unsafe"
+)
+
+// Token is an access token for obtaining kstats.
+type Token struct {
+	kc *C.struct_kstat_ctl
+
+	// ksm maps kstat_t pointers to our Go-level KStats for them.
+	// kstat_t's stay constant over the lifetime of a token, so
+	// we want to keep unique KStats. This holds some Go-level
+	// memory down, but I wave my hands.
+	ksm map[*C.struct_kstat]*KStat
+}
+
+// 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 Open() (*Token, error) {
+	r, err := C.kstat_open()
+	if r == nil {
+		return nil, err
+	}
+	t := Token{}
+	t.kc = r
+	t.ksm = make(map[*C.struct_kstat]*KStat)
+	// A 'func (t *Token) Close()' is equivalent to
+	// 'func Close(t *Token)'. The latter is what SetFinalizer()
+	// needs.
+	runtime.SetFinalizer(&t, (*Token).Close)
+	return &t, nil
+}
+
+// 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) Close() error {
+	if t == nil || t.kc == nil {
+		return nil
+	}
+
+	// Go through our KStats and null out fields that are no longer
+	// valid. We opt to do this before we actually destroy the memory
+	// KStat.ksp is pointing to by calling kstat_close().
+	for _, v := range t.ksm {
+		v.ksp = nil
+		v.tok = nil
+	}
+
+	res, err := C.kstat_close(t.kc)
+	t.kc = nil
+
+	// clear the map to drop all references to KStats.
+	t.ksm = make(map[*C.struct_kstat]*KStat)
+
+	// cancel finalizer
+	runtime.SetFinalizer(&t, nil)
+
+	if res != 0 {
+		return err
+	}
+	return nil
+}
+
+// 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 (t *Token) Update() (bool, error) {
+	if t == nil || t.kc == nil {
+		return true, errors.New("token is closed")
+	}
+	oid := t.kc.kc_chain_id
+	// NOTE that we can't assume err == nil on success and just
+	// check for err != nil. The error return is set from errno,
+	// and kstat_chain_update() does not guarantee that errno is
+	// 0 if it succeeds.
+	nid, err := C.kstat_chain_update(t.kc)
+	switch {
+	case nid < 0:
+		// We generously assume that if there has been an
+		// error, the chain is intact. Otherwise we should
+		// invalidate all KStats in t.ksm, as in .Close().
+		// assumption: err != nil if n < 0.
+		return false, err
+	case nid == 0:
+		// No change is good news.
+		return false, nil
+	case nid == oid:
+		// Should never be the case, but...
+		return false, fmt.Errorf("new KCID is old KCID: %d", nid)
+	}
+
+	// The simple approach to KStats after a chain update would be
+	// to invalidate all existing KStats. However, we can do
+	// better. kstat_chain_update() implicitly guarantees that it
+	// will not reuse memory addresses of kstat_t structures for
+	// different ones within a single call, so we can walk the
+	// chain and look for addresses that we already know; the
+	// KStats for those addresses are still valid.
+
+	// Copy all valid chain entries that we have in the token ksm
+	// map to a new map and delete them from the old (current) map.
+	nksm := make(map[*C.struct_kstat]*KStat)
+	for r := t.kc.kc_chain; r != nil; r = r.ks_next {
+		if v, ok := t.ksm[r]; ok {
+			nksm[r] = v
+			delete(t.ksm, r)
+		}
+	}
+	// Anything left in t.ksm is an old chain entry that was
+	// removed by kstat_chain_update(). Explicitly zap their
+	// KStat's references to make them invalid.
+	for _, v := range t.ksm {
+		v.ksp = nil
+		v.tok = nil
+	}
+	// Make our new ksm map the current ksm map.
+	t.ksm = nksm
+
+	return true, nil
+}
+
+// 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) All() []*KStat {
+	n := []*KStat{}
+	if t == nil || t.kc == nil {
+		return n
+	}
+
+	for r := t.kc.kc_chain; r != nil; r = r.ks_next {
+		n = append(n, newKStat(t, r))
+	}
+	return n
+}
+
+//
+// allocate a C string for a non-blank string; otherwise return nil
+func maybeCString(src string) *C.char {
+	if src == "" {
+		return nil
+	}
+	return C.CString(src)
+}
+
+// free a non-nil C string
+func maybeFree(cs *C.char) {
+	if cs != nil {
+		C.free(unsafe.Pointer(cs))
+	}
+}
+
+// strndup behaves like the C function; given a *C.char and a len, it
+// returns a string that is up to len characters long at most.
+// Shorn of casts, it is:
+//	C.GoStringN(p, C.strnlen(p, len))
+//
+// strndup() is necessary to copy fields of the type 'char
+// name[SIZE];' where a string of exactly SIZE length will not be
+// null-terminated. GoStringN() will always copy trailing null bytes
+// and other garbage; GoString()'s internal strlen() may run off the
+// end of the 'name' field and either fault or copy too much.
+func strndup(cs *C.char, len C.size_t) string {
+	// credit: Ian Lance Taylor in
+	// https://github.com/golang/go/issues/12428
+	return C.GoStringN(cs, C.int(C.strnlen(cs, len)))
+}
+
+// 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 (t *Token) Lookup(module string, instance int, name string) (*KStat, error) {
+	if t == nil || t.kc == nil {
+		return nil, errors.New("Token not valid or closed")
+	}
+
+	ms := maybeCString(module)
+	ns := maybeCString(name)
+	r, err := C.kstat_lookup(t.kc, ms, C.int(instance), ns)
+	maybeFree(ms)
+	maybeFree(ns)
+
+	if r == nil {
+		return nil, err
+	}
+
+	k := newKStat(t, r)
+
+	// People rarely look up kstats to not use them, so we immediately
+	// attempt to kstat_read() the data. If this fails, we don't return
+	// the kstat. However, we don't scrub it from the kstat_t mapping
+	// that the Token maintains; we have no reason to believe that it
+	// needs to be remade. Our return of nil is a convenience to avoid
+	// problems in callers.
+	// TODO: this may be a mistake in the API.
+	//
+	// NOTE: this means that calling Lookup() on an existing KStat
+	// (either directly or via tok.GetNamed()) has the effect of
+	// updating its statistics data to the current time. Right now
+	// we consider this a feature.
+	err = k.Refresh()
+	if err != nil {
+		return nil, err
+	}
+	return k, nil
+}
+
+// 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 statistic.
+//
+// It is equivalent to .Lookup() then KStat.GetNamed().
+func (t *Token) GetNamed(module string, instance int, name, stat string) (*Named, error) {
+	stats, err := t.Lookup(module, instance, name)
+	if err != nil {
+		return nil, err
+	}
+	return stats.GetNamed(stat)
+}
+
+// -----
+
+// KSType is the type of the data in a KStat.
+type KSType int
+
+// 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 statistics.
+const (
+	RawStat   KSType = C.KSTAT_TYPE_RAW
+	NamedStat KSType = C.KSTAT_TYPE_NAMED
+	IntrStat  KSType = C.KSTAT_TYPE_INTR
+	IoStat    KSType = C.KSTAT_TYPE_IO
+	TimerStat KSType = C.KSTAT_TYPE_TIMER
+)
+
+func (tp KSType) String() string {
+	switch tp {
+	case RawStat:
+		return "raw"
+	case NamedStat:
+		return "named"
+	case IntrStat:
+		return "interrupt"
+	case IoStat:
+		return "io"
+	case TimerStat:
+		return "timer"
+	default:
+		return fmt.Sprintf("kstat_type:%d", tp)
+	}
+}
+
+// KStat is the access handle for the collection of statistics for a
+// particular module:instance:name kstat.
+//
+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
+
+	ksp *C.struct_kstat
+	// We need access to the token to refresh the data
+	tok *Token
+}
+
+// newKStat is our internal KStat constructor.
+//
+// This also has the responsibility of maintaining (and using) the
+// kstat_t to KStat mapping cache, so that we don't recreate new
+// KStats for the same kstat_t all the time.
+func newKStat(tok *Token, ks *C.struct_kstat) *KStat {
+	if kst, ok := tok.ksm[ks]; ok {
+		return kst
+	}
+
+	kst := KStat{}
+	kst.ksp = ks
+	kst.tok = tok
+
+	kst.Instance = int(ks.ks_instance)
+	kst.Module = strndup((*C.char)(unsafe.Pointer(&ks.ks_module)), C.KSTAT_STRLEN)
+	kst.Name = strndup((*C.char)(unsafe.Pointer(&ks.ks_name)), C.KSTAT_STRLEN)
+	kst.Class = strndup((*C.char)(unsafe.Pointer(&ks.ks_class)), C.KSTAT_STRLEN)
+	kst.Type = KSType(ks.ks_type)
+	kst.Crtime = int64(ks.ks_crtime)
+
+	// Inside the kernel, the ks_snaptime of a kstat is of course
+	// a global thing. This 'global' snaptime is copied to user
+	// level as part of the kstat header(s) on kstat_open(), which
+	// means that kstats that have never been kstat_read() by us
+	// are almost certain to have a non-zero ks_snaptime (because
+	// someone, somewhere, will have read them since the system
+	// booted, eg 'kstat -p | grep ...'  reads all kstats).
+	// Because this ks_snaptime is not useful, we don't copy it
+	// to Snaptime; instead we leave Snaptime unset (zero) as
+	// an explicit signal that this KStat has never had its data
+	// read.
+	//
+	//kst.Snaptime = int64(ks.ks_snaptime)
+
+	tok.ksm[ks] = &kst
+	return &kst
+}
+
+// invalid is a desperate attempt to keep usage errors from causing
+// memory corruption. Don't count on it.
+func (k *KStat) invalid() bool {
+	return k == nil || k.ksp == nil || k.tok == nil || k.tok.kc == nil
+}
+
+// setup does validity checks and setup, such as loading data via Refresh().
+// It applies only to named kstats.
+//
+// TODO: setup() vs prep() is a code smell.
+func (k *KStat) setup() error {
+	if k.invalid() {
+		return errors.New("invalid KStat or closed token")
+	}
+
+	if k.ksp.ks_type != C.KSTAT_TYPE_NAMED {
+		return fmt.Errorf("kstat %s (type %d) is not a named kstat", k, k.ksp.ks_type)
+	}
+
+	// Do the initial load of the data if necessary.
+	if k.ksp.ks_data == nil {
+		if err := k.Refresh(); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func (k *KStat) String() string {
+	return fmt.Sprintf("%s:%d:%s (%s)", k.Module, k.Instance, k.Name, k.Class)
+}
+
+// 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.
+func (k *KStat) Valid() bool {
+	return !k.invalid()
+}
+
+// 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) Refresh() error {
+	if k.invalid() {
+		return errors.New("invalid KStat or closed token")
+	}
+
+	res, err := C.kstat_read(k.tok.kc, k.ksp, nil)
+	if res == -1 {
+		return err
+	}
+	k.Snaptime = int64(k.ksp.ks_snaptime)
+	return nil
+}
+
+// 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) GetIO() (*IO, error) {
+	if err := k.Refresh(); err != nil {
+		return nil, err
+	}
+	if k.ksp.ks_type != C.KSTAT_TYPE_IO {
+		return nil, fmt.Errorf("kstat %s (type %d) is not an IO kstat", k, k.ksp.ks_type)
+	}
+
+	// We make our own copy of ks_data (as an IO) so that we don't
+	// point into C-owned memory. 'go tool cgo -godef' apparently
+	// guarantees that the IO struct/type it creates has exactly
+	// the same in-memory layout as the C struct, so we can safely
+	// do this copy and expect to get good results.
+	io := IO{}
+	io = *((*IO)(k.ksp.ks_data))
+	return &io, nil
+}
+
+// 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) GetNamed(name string) (*Named, error) {
+	if err := k.setup(); err != nil {
+		return nil, err
+	}
+	ns := C.CString(name)
+	r, err := C.kstat_data_lookup(k.ksp, ns)
+	C.free(unsafe.Pointer(ns))
+	if r == nil || err != nil {
+		return nil, err
+	}
+	return newNamed(k, (*C.struct_kstat_named)(r)), err
+}
+
+// AllNamed returns an array of all named statistics for a particular
+// named-type KStat. Entries are returned in no particular order.
+func (k *KStat) AllNamed() ([]*Named, error) {
+	if err := k.setup(); err != nil {
+		return nil, err
+	}
+	lst := make([]*Named, k.ksp.ks_ndata)
+	for i := C.uint_t(0); i < k.ksp.ks_ndata; i++ {
+		ks := C.get_nth_named(k.ksp, i)
+		if ks == nil {
+			panic("get_nth_named returned surprise nil")
+		}
+		lst[i] = newNamed(k, ks)
+	}
+	return lst, nil
+}
+
+// Named represents a particular kstat named statistic, ie the full
+//	module:instance:name:statistic
+// 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.
+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
+}
+
+func (ks *Named) String() string {
+	return fmt.Sprintf("%s:%d:%s:%s", ks.KStat.Module, ks.KStat.Instance, ks.KStat.Name, ks.Name)
+}
+
+// NamedType represents the various types of named kstat statistics.
+type NamedType int
+
+// The different types of data that a named kstat statistic can be
+// (ie, these are the potential values of Named.Type).
+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
+
+	// CharData is found in StringVal. At the moment we assume that
+	// it is a real string, because this matches how it seems to be
+	// used for short strings in the Solaris kernel. Someday we may
+	// find something that uses it as just a data dump for 16 bytes.
+
+	// Solaris sys/kstat.h also has _FLOAT (5) and _DOUBLE (6) types,
+	// but labels them as obsolete.
+)
+
+func (tp NamedType) String() string {
+	switch tp {
+	case CharData:
+		return "char"
+	case Int32:
+		return "int32"
+	case Uint32:
+		return "uint32"
+	case Int64:
+		return "int64"
+	case Uint64:
+		return "uint64"
+	case String:
+		return "string"
+	default:
+		return fmt.Sprintf("named_type-%d", tp)
+	}
+}
+
+// Create a new Stat from the kstat_named_t
+// We set the appropriate *Value field.
+func newNamed(k *KStat, knp *C.struct_kstat_named) *Named {
+	st := Named{}
+	st.KStat = k
+	st.Name = strndup((*C.char)(unsafe.Pointer(&knp.name)), C.KSTAT_STRLEN)
+	st.Type = NamedType(knp.data_type)
+	st.Snaptime = k.Snaptime
+
+	switch st.Type {
+	case String:
+		// The comments in sys/kstat.h explicitly guarantee
+		// that these strings are null-terminated, although
+		// knp.value.str.len also holds the length.
+		st.StringVal = C.GoString(C.get_named_char(knp))
+	case CharData:
+		// Solaris/etc appears to use CharData for short strings
+		// so that they can be embedded directly into
+		// knp.value.c[16] instead of requiring an out of line
+		// allocation. In theory we may find someone who is
+		// using it as 128-bit ints or the like.
+		// However I scanned the Illumos kernel source and
+		// everyone using it appears to really be using it for
+		// strings.
+		st.StringVal = strndup((*C.char)(unsafe.Pointer(&knp.value)), 16)
+	case Int32, Int64:
+		st.IntVal = int64(C.get_named_int(knp))
+	case Uint32, Uint64:
+		st.UintVal = uint64(C.get_named_uint(knp))
+	default:
+		// TODO: should do better.
+		panic(fmt.Sprintf("unknown stat type: %d", st.Type))
+	}
+	return &st
+}
diff --git a/vendor/github.com/siebenmann/go-kstat/raw_solaris.go b/vendor/github.com/siebenmann/go-kstat/raw_solaris.go
new file mode 100644
index 00000000..98d71187
--- /dev/null
+++ b/vendor/github.com/siebenmann/go-kstat/raw_solaris.go
@@ -0,0 +1,236 @@
+//
+// Really raw access to KStat data
+
+package kstat
+
+// #cgo LDFLAGS: -lkstat
+//
+// #include <sys/types.h>
+// #include <stdlib.h>
+// #include <strings.h>
+// #include <kstat.h>
+// #include <nfs/nfs_clnt.h>
+//
+import "C"
+import (
+	"errors"
+	"fmt"
+	"reflect"
+	"unsafe"
+)
+
+// 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 Raw struct {
+	Data     []byte
+	Ndata    uint64
+	Snaptime int64
+	KStat    *KStat
+}
+
+// TODO: better functionality split here
+func (k *KStat) prep() error {
+	if k.invalid() {
+		return errors.New("invalid KStat or closed token")
+	}
+
+	// Do the initial load of the data if necessary.
+	if k.ksp.ks_data == nil {
+		if err := k.Refresh(); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// 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) Raw() (*Raw, error) {
+	if err := k.prep(); err != nil {
+		return nil, err
+	}
+	r := Raw{}
+	r.KStat = k
+	r.Snaptime = k.Snaptime
+	r.Ndata = uint64(k.ksp.ks_ndata)
+	// The forced C.int() conversion is dangerous, because C.int
+	// is not necessarily large enough to contain a
+	// size_t. However this is the interface that Go gives us, so
+	// we live with it.
+	r.Data = C.GoBytes(unsafe.Pointer(k.ksp.ks_data), C.int(k.ksp.ks_data_size))
+	return &r, nil
+}
+
+func (tok *Token) prepunix(name string, size uintptr) (*KStat, error) {
+	k, err := tok.Lookup("unix", 0, name)
+	if err != nil {
+		return nil, err
+	}
+	// TODO: handle better?
+	if k.ksp.ks_type != C.KSTAT_TYPE_RAW {
+		return nil, fmt.Errorf("%s is wrong type %s", k, k.Type)
+	}
+	if uintptr(k.ksp.ks_data_size) != size {
+		return nil, fmt.Errorf("%s is wrong size %d (should be %d)", k, k.ksp.ks_data_size, size)
+	}
+	return k, nil
+}
+
+// Sysinfo returns the KStat and the statistics from unix:0:sysinfo.
+// It always returns a current, refreshed copy.
+func (tok *Token) Sysinfo() (*KStat, *Sysinfo, error) {
+	var si Sysinfo
+	k, err := tok.prepunix("sysinfo", unsafe.Sizeof(si))
+	if err != nil {
+		return nil, nil, err
+	}
+	si = *((*Sysinfo)(k.ksp.ks_data))
+	return k, &si, nil
+}
+
+// Vminfo returns the KStat and the statistics from unix:0:vminfo.
+// It always returns a current, refreshed copy.
+func (tok *Token) Vminfo() (*KStat, *Vminfo, error) {
+	var vi Vminfo
+	k, err := tok.prepunix("vminfo", unsafe.Sizeof(vi))
+	if err != nil {
+		return nil, nil, err
+	}
+	vi = *((*Vminfo)(k.ksp.ks_data))
+	return k, &vi, nil
+}
+
+// Var returns the KStat and the statistics from unix:0:var.
+// It always returns a current, refreshed copy.
+func (tok *Token) Var() (*KStat, *Var, error) {
+	var vi Var
+	k, err := tok.prepunix("var", unsafe.Sizeof(vi))
+	if err != nil {
+		return nil, nil, err
+	}
+	vi = *((*Var)(k.ksp.ks_data))
+	return k, &vi, nil
+}
+
+// GetMntinfo retrieves a Mntinfo struct from a nfs:*:mntinfo KStat.
+// It does not force a refresh of the KStat.
+func (k *KStat) GetMntinfo() (*Mntinfo, error) {
+	var mi Mntinfo
+	if err := k.prep(); err != nil {
+		return nil, err
+	}
+	if k.Type != RawStat || k.Module != "nfs" || k.Name != "mntinfo" {
+		return nil, errors.New("KStat is not a Mntinfo kstat")
+	}
+	if uintptr(k.ksp.ks_data_size) != unsafe.Sizeof(mi) {
+		return nil, fmt.Errorf("KStat is wrong size %d (should be %d)", k.ksp.ks_data_size, unsafe.Sizeof(mi))
+	}
+	mi = *((*Mntinfo)(k.ksp.ks_data))
+	return &mi, nil
+}
+
+//
+// Support for copying semi-arbitrary structures out of raw
+// KStats.
+//
+
+// safeThing returns true if a given type is either a simple defined
+// size primitive integer type or an array and/or struct composed
+// entirely of safe things. A safe thing is entirely self contained
+// and may be initialized from random memory without breaking Go's
+// memory safety (although the values it contains may be garbage).
+//
+func safeThing(t reflect.Type) bool {
+	switch t.Kind() {
+	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		return true
+	case reflect.Array:
+		// an array is safe if it's an array of something safe
+		return safeThing(t.Elem())
+	case reflect.Struct:
+		// a struct is safe if all its components are safe
+		for i := 0; i < t.NumField(); i++ {
+			if !safeThing(t.Field(i).Type) {
+				return false
+			}
+		}
+		return true
+	default:
+		// other things are not safe.
+		return false
+	}
+}
+
+// TODO: add floats to the supported list? It's unlikely to be needed
+// but it should just work.
+
+// 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 data.
+//
+// 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) CopyTo(ptr interface{}) error {
+	if err := k.prep(); err != nil {
+		return err
+	}
+
+	if k.Type != RawStat {
+		return errors.New("KStat is not a RawStat")
+	}
+
+	// Validity checks: not nil value, not nil pointer value,
+	// is a pointer to struct.
+	if ptr == nil {
+		panic("CopyTo given nil pointer")
+	}
+	vp := reflect.ValueOf(ptr)
+	if vp.Kind() != reflect.Ptr {
+		panic("CopyTo not given a pointer")
+	}
+	if vp.IsNil() {
+		panic("CopyTo given nil pointer")
+	}
+	dst := vp.Elem()
+	if dst.Kind() != reflect.Struct {
+		panic("CopyTo: not pointer to struct")
+	}
+	// Is the struct safe to copy into, which means primitive types
+	// and structs/arrays of primitive types?
+	if !safeThing(dst.Type()) {
+		panic("CopyTo: not a safe structure, contains unsupported fields")
+	}
+	if !dst.CanSet() {
+		panic("CopyTo: struct cannot be set for some reason")
+	}
+
+	// Verify that the size of the target struct matches the size
+	// of the raw KStat.
+	if uintptr(k.ksp.ks_data_size) != dst.Type().Size() {
+		return errors.New("struct size does not match KStat size")
+	}
+
+	// The following is exactly the magic that we performed for
+	// specific types earlier. We take k.ksp.ks_data and turn
+	// it into a typed pointer to the target object's type:
+	//
+	//	src := ((*<type>)(k.kps.ks_data))
+	src := reflect.NewAt(dst.Type(), unsafe.Pointer(k.ksp.ks_data))
+
+	// We now dereference that into the destination to copy the
+	// data:
+	//
+	//	dst = *src
+	dst.Set(reflect.Indirect(src))
+
+	return nil
+}
diff --git a/vendor/github.com/siebenmann/go-kstat/types_solaris_amd64.go b/vendor/github.com/siebenmann/go-kstat/types_solaris_amd64.go
new file mode 100644
index 00000000..bea09608
--- /dev/null
+++ b/vendor/github.com/siebenmann/go-kstat/types_solaris_amd64.go
@@ -0,0 +1,141 @@
+//
+// Initially created by
+//	cgo -godefs ctypes_solaris.go
+//
+// Now contains edits for documentation. This is considered okay by me
+// because these structs are not exactly likely to change any time
+// soon; that would break API compatibility.
+//
+// This is specific to amd64. It's unlikely that Go will support
+// 32-bit Solaris ('386'), but.
+
+package kstat
+
+// 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 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
+}
+
+// Sysinfo is the data from unix:0:sysinfo, which is a sysinfo_t.
+type Sysinfo struct {
+	Updates uint32
+	Runque  uint32
+	Runocc  uint32
+	Swpque  uint32
+	Swpocc  uint32
+	Waiting uint32
+}
+
+// Vminfo is the data from unix:0:vminfo, which is a vminfo_t.
+type Vminfo struct {
+	Freemem uint64
+	Resv    uint64
+	Alloc   uint64
+	Avail   uint64
+	Free    uint64
+	Updates uint64
+}
+
+// Var is the data from unix:0:var, which is a 'struct var'.
+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
+}
+
+// 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.
+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
+	pad0       [3]byte
+}
+
+// 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.)
+func CFieldString(src []int8) string {
+	slen := len(src)
+	buf := make([]byte, slen)
+	for i := 0; i < len(src); i++ {
+		buf[i] = byte(src[i])
+		if src[i] == 0 {
+			slen = i
+			break
+		}
+	}
+	return string(buf[:slen])
+}
+
+// Proto returns a Mntinfo RProto as a string.
+func (m Mntinfo) Proto() string {
+	return CFieldString(m.RProto[:])
+}
+
+// Curserver returns a Mntinfo RCurserver as a string.
+func (m Mntinfo) Curserver() string {
+	return CFieldString(m.RCurserver[:])
+}
+
+// The Mntinfo type is not an exact conversion as produced by cgo;
+// because the original struct mntinfo_kstat contains an embedded
+// anonymously typed struct, it runs into
+// https://github.com/golang/go/issues/5253. This version is manually
+// produced from a cgo starting point and then verified to be the same
+// size.
+// It also has Proto and Curserver renamed so we can add methods to
+// get them as Go strings.
diff --git a/vendor/modules.txt b/vendor/modules.txt
index dbd7d5f7..25bff14e 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -43,7 +43,7 @@ github.com/prometheus/common/version
 github.com/prometheus/common/expfmt
 github.com/prometheus/common/model
 github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg
-# github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d
+# github.com/prometheus/procfs v0.0.0-20190129233650-316cf8ccfec5
 github.com/prometheus/procfs
 github.com/prometheus/procfs/bcache
 github.com/prometheus/procfs/nfs