From 38d3515676686736010c34b003acb520cbf6810e Mon Sep 17 00:00:00 2001 From: Khanh Pham Date: Fri, 25 Oct 2019 12:03:22 +0700 Subject: [PATCH 1/6] remove dep --- .gitignore | 2 + Gopkg.lock | 69 - Gopkg.toml | 38 - vendor/github.com/beorn7/perks/LICENSE | 20 - .../beorn7/perks/quantile/exampledata.txt | 2388 ------- .../beorn7/perks/quantile/stream.go | 292 - vendor/github.com/golang/protobuf/AUTHORS | 3 - .../github.com/golang/protobuf/CONTRIBUTORS | 3 - vendor/github.com/golang/protobuf/LICENSE | 31 - .../github.com/golang/protobuf/proto/Makefile | 43 - .../github.com/golang/protobuf/proto/clone.go | 229 - .../golang/protobuf/proto/decode.go | 970 --- .../golang/protobuf/proto/discard.go | 151 - .../golang/protobuf/proto/encode.go | 1362 ---- .../github.com/golang/protobuf/proto/equal.go | 300 - .../golang/protobuf/proto/extensions.go | 587 -- .../github.com/golang/protobuf/proto/lib.go | 897 --- .../golang/protobuf/proto/message_set.go | 311 - .../golang/protobuf/proto/pointer_reflect.go | 484 -- .../golang/protobuf/proto/pointer_unsafe.go | 270 - .../golang/protobuf/proto/properties.go | 872 --- .../github.com/golang/protobuf/proto/text.go | 854 --- .../golang/protobuf/proto/text_parser.go | 895 --- .../golang_protobuf_extensions/LICENSE | 201 - .../golang_protobuf_extensions/NOTICE | 1 - .../pbutil/decode.go | 75 - .../golang_protobuf_extensions/pbutil/doc.go | 16 - .../pbutil/encode.go | 46 - vendor/github.com/mindprince/gonvml/LICENSE | 202 - vendor/github.com/mindprince/gonvml/Makefile | 20 - .../github.com/mindprince/gonvml/NVML_NOTICE | 32 - vendor/github.com/mindprince/gonvml/README.md | 19 - .../github.com/mindprince/gonvml/bindings.go | 476 -- vendor/github.com/mindprince/gonvml/nvml.h | 5605 ----------------- .../prometheus/client_golang/AUTHORS.md | 18 - .../prometheus/client_golang/LICENSE | 201 - .../prometheus/client_golang/NOTICE | 23 - .../client_golang/prometheus/.gitignore | 1 - .../client_golang/prometheus/README.md | 1 - .../client_golang/prometheus/collector.go | 75 - .../client_golang/prometheus/counter.go | 172 - .../client_golang/prometheus/desc.go | 205 - .../client_golang/prometheus/doc.go | 181 - .../prometheus/expvar_collector.go | 119 - .../client_golang/prometheus/fnv.go | 29 - .../client_golang/prometheus/gauge.go | 140 - .../client_golang/prometheus/go_collector.go | 263 - .../client_golang/prometheus/histogram.go | 444 -- .../client_golang/prometheus/http.go | 490 -- .../client_golang/prometheus/metric.go | 166 - .../prometheus/process_collector.go | 142 - .../client_golang/prometheus/promhttp/http.go | 201 - .../client_golang/prometheus/registry.go | 806 --- .../client_golang/prometheus/summary.go | 534 -- .../client_golang/prometheus/untyped.go | 138 - .../client_golang/prometheus/value.go | 234 - .../client_golang/prometheus/vec.go | 404 -- .../prometheus/client_model/LICENSE | 201 - .../github.com/prometheus/client_model/NOTICE | 5 - .../prometheus/client_model/go/metrics.pb.go | 364 -- .../prometheus/client_model/ruby/LICENSE | 201 - vendor/github.com/prometheus/common/LICENSE | 201 - vendor/github.com/prometheus/common/NOTICE | 5 - .../prometheus/common/expfmt/decode.go | 429 -- .../prometheus/common/expfmt/encode.go | 88 - .../prometheus/common/expfmt/expfmt.go | 38 - .../prometheus/common/expfmt/fuzz.go | 36 - .../prometheus/common/expfmt/text_create.go | 303 - .../prometheus/common/expfmt/text_parse.go | 757 --- .../bitbucket.org/ww/goautoneg/README.txt | 67 - .../bitbucket.org/ww/goautoneg/autoneg.go | 162 - .../prometheus/common/model/alert.go | 136 - .../prometheus/common/model/fingerprinting.go | 105 - .../github.com/prometheus/common/model/fnv.go | 42 - .../prometheus/common/model/labels.go | 210 - .../prometheus/common/model/labelset.go | 169 - .../prometheus/common/model/metric.go | 103 - .../prometheus/common/model/model.go | 16 - .../prometheus/common/model/signature.go | 144 - .../prometheus/common/model/silence.go | 106 - .../prometheus/common/model/time.go | 264 - .../prometheus/common/model/value.go | 416 -- .../github.com/prometheus/procfs/.travis.yml | 9 - .../prometheus/procfs/CONTRIBUTING.md | 18 - vendor/github.com/prometheus/procfs/LICENSE | 201 - .../prometheus/procfs/MAINTAINERS.md | 1 - vendor/github.com/prometheus/procfs/Makefile | 18 - vendor/github.com/prometheus/procfs/NOTICE | 7 - vendor/github.com/prometheus/procfs/README.md | 11 - .../github.com/prometheus/procfs/buddyinfo.go | 95 - vendor/github.com/prometheus/procfs/doc.go | 45 - .../prometheus/procfs/fixtures/26231/exe | 1 - .../prometheus/procfs/fixtures/26231/fd/0 | 1 - .../prometheus/procfs/fixtures/26231/fd/1 | 1 - .../prometheus/procfs/fixtures/26231/fd/10 | 1 - .../prometheus/procfs/fixtures/26231/fd/2 | 1 - .../prometheus/procfs/fixtures/26231/fd/3 | 1 - .../prometheus/procfs/fixtures/26231/ns/mnt | 1 - .../prometheus/procfs/fixtures/26231/ns/net | 1 - .../prometheus/procfs/fixtures/26232/fd/0 | 1 - .../prometheus/procfs/fixtures/26232/fd/1 | 1 - .../prometheus/procfs/fixtures/26232/fd/2 | 1 - .../prometheus/procfs/fixtures/26232/fd/3 | 1 - .../prometheus/procfs/fixtures/26232/fd/4 | 1 - .../prometheus/procfs/fixtures/self | 1 - vendor/github.com/prometheus/procfs/fs.go | 69 - .../prometheus/procfs/internal/util/parse.go | 46 - vendor/github.com/prometheus/procfs/ipvs.go | 246 - vendor/github.com/prometheus/procfs/mdstat.go | 138 - .../prometheus/procfs/mountstats.go | 556 -- .../github.com/prometheus/procfs/net_dev.go | 203 - .../github.com/prometheus/procfs/nfs/nfs.go | 263 - .../github.com/prometheus/procfs/nfs/parse.go | 308 - .../prometheus/procfs/nfs/parse_nfs.go | 67 - .../prometheus/procfs/nfs/parse_nfsd.go | 89 - vendor/github.com/prometheus/procfs/proc.go | 224 - .../github.com/prometheus/procfs/proc_io.go | 52 - .../prometheus/procfs/proc_limits.go | 137 - .../github.com/prometheus/procfs/proc_ns.go | 55 - .../github.com/prometheus/procfs/proc_stat.go | 175 - vendor/github.com/prometheus/procfs/stat.go | 219 - vendor/github.com/prometheus/procfs/ttar | 264 - vendor/github.com/prometheus/procfs/xfrm.go | 187 - .../github.com/prometheus/procfs/xfs/parse.go | 330 - .../github.com/prometheus/procfs/xfs/xfs.go | 163 - 125 files changed, 2 insertions(+), 31527 deletions(-) create mode 100644 .gitignore delete mode 100644 Gopkg.lock delete mode 100644 Gopkg.toml delete mode 100644 vendor/github.com/beorn7/perks/LICENSE delete mode 100644 vendor/github.com/beorn7/perks/quantile/exampledata.txt delete mode 100644 vendor/github.com/beorn7/perks/quantile/stream.go delete mode 100644 vendor/github.com/golang/protobuf/AUTHORS delete mode 100644 vendor/github.com/golang/protobuf/CONTRIBUTORS delete mode 100644 vendor/github.com/golang/protobuf/LICENSE delete mode 100644 vendor/github.com/golang/protobuf/proto/Makefile delete mode 100644 vendor/github.com/golang/protobuf/proto/clone.go delete mode 100644 vendor/github.com/golang/protobuf/proto/decode.go delete mode 100644 vendor/github.com/golang/protobuf/proto/discard.go delete mode 100644 vendor/github.com/golang/protobuf/proto/encode.go delete mode 100644 vendor/github.com/golang/protobuf/proto/equal.go delete mode 100644 vendor/github.com/golang/protobuf/proto/extensions.go delete mode 100644 vendor/github.com/golang/protobuf/proto/lib.go delete mode 100644 vendor/github.com/golang/protobuf/proto/message_set.go delete mode 100644 vendor/github.com/golang/protobuf/proto/pointer_reflect.go delete mode 100644 vendor/github.com/golang/protobuf/proto/pointer_unsafe.go delete mode 100644 vendor/github.com/golang/protobuf/proto/properties.go delete mode 100644 vendor/github.com/golang/protobuf/proto/text.go delete mode 100644 vendor/github.com/golang/protobuf/proto/text_parser.go delete mode 100644 vendor/github.com/matttproud/golang_protobuf_extensions/LICENSE delete mode 100644 vendor/github.com/matttproud/golang_protobuf_extensions/NOTICE delete mode 100644 vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/decode.go delete mode 100644 vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/doc.go delete mode 100644 vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/encode.go delete mode 100644 vendor/github.com/mindprince/gonvml/LICENSE delete mode 100644 vendor/github.com/mindprince/gonvml/Makefile delete mode 100644 vendor/github.com/mindprince/gonvml/NVML_NOTICE delete mode 100644 vendor/github.com/mindprince/gonvml/README.md delete mode 100644 vendor/github.com/mindprince/gonvml/bindings.go delete mode 100644 vendor/github.com/mindprince/gonvml/nvml.h delete mode 100644 vendor/github.com/prometheus/client_golang/AUTHORS.md delete mode 100644 vendor/github.com/prometheus/client_golang/LICENSE delete mode 100644 vendor/github.com/prometheus/client_golang/NOTICE delete mode 100644 vendor/github.com/prometheus/client_golang/prometheus/.gitignore delete mode 100644 vendor/github.com/prometheus/client_golang/prometheus/README.md delete mode 100644 vendor/github.com/prometheus/client_golang/prometheus/collector.go delete mode 100644 vendor/github.com/prometheus/client_golang/prometheus/counter.go delete mode 100644 vendor/github.com/prometheus/client_golang/prometheus/desc.go delete mode 100644 vendor/github.com/prometheus/client_golang/prometheus/doc.go delete mode 100644 vendor/github.com/prometheus/client_golang/prometheus/expvar_collector.go delete mode 100644 vendor/github.com/prometheus/client_golang/prometheus/fnv.go delete mode 100644 vendor/github.com/prometheus/client_golang/prometheus/gauge.go delete mode 100644 vendor/github.com/prometheus/client_golang/prometheus/go_collector.go delete mode 100644 vendor/github.com/prometheus/client_golang/prometheus/histogram.go delete mode 100644 vendor/github.com/prometheus/client_golang/prometheus/http.go delete mode 100644 vendor/github.com/prometheus/client_golang/prometheus/metric.go delete mode 100644 vendor/github.com/prometheus/client_golang/prometheus/process_collector.go delete mode 100644 vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go delete mode 100644 vendor/github.com/prometheus/client_golang/prometheus/registry.go delete mode 100644 vendor/github.com/prometheus/client_golang/prometheus/summary.go delete mode 100644 vendor/github.com/prometheus/client_golang/prometheus/untyped.go delete mode 100644 vendor/github.com/prometheus/client_golang/prometheus/value.go delete mode 100644 vendor/github.com/prometheus/client_golang/prometheus/vec.go delete mode 100644 vendor/github.com/prometheus/client_model/LICENSE delete mode 100644 vendor/github.com/prometheus/client_model/NOTICE delete mode 100644 vendor/github.com/prometheus/client_model/go/metrics.pb.go delete mode 100644 vendor/github.com/prometheus/client_model/ruby/LICENSE delete mode 100644 vendor/github.com/prometheus/common/LICENSE delete mode 100644 vendor/github.com/prometheus/common/NOTICE delete mode 100644 vendor/github.com/prometheus/common/expfmt/decode.go delete mode 100644 vendor/github.com/prometheus/common/expfmt/encode.go delete mode 100644 vendor/github.com/prometheus/common/expfmt/expfmt.go delete mode 100644 vendor/github.com/prometheus/common/expfmt/fuzz.go delete mode 100644 vendor/github.com/prometheus/common/expfmt/text_create.go delete mode 100644 vendor/github.com/prometheus/common/expfmt/text_parse.go delete mode 100644 vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/README.txt delete mode 100644 vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go delete mode 100644 vendor/github.com/prometheus/common/model/alert.go delete mode 100644 vendor/github.com/prometheus/common/model/fingerprinting.go delete mode 100644 vendor/github.com/prometheus/common/model/fnv.go delete mode 100644 vendor/github.com/prometheus/common/model/labels.go delete mode 100644 vendor/github.com/prometheus/common/model/labelset.go delete mode 100644 vendor/github.com/prometheus/common/model/metric.go delete mode 100644 vendor/github.com/prometheus/common/model/model.go delete mode 100644 vendor/github.com/prometheus/common/model/signature.go delete mode 100644 vendor/github.com/prometheus/common/model/silence.go delete mode 100644 vendor/github.com/prometheus/common/model/time.go delete mode 100644 vendor/github.com/prometheus/common/model/value.go delete mode 100644 vendor/github.com/prometheus/procfs/.travis.yml delete mode 100644 vendor/github.com/prometheus/procfs/CONTRIBUTING.md delete mode 100644 vendor/github.com/prometheus/procfs/LICENSE delete mode 100644 vendor/github.com/prometheus/procfs/MAINTAINERS.md delete mode 100644 vendor/github.com/prometheus/procfs/Makefile delete mode 100644 vendor/github.com/prometheus/procfs/NOTICE delete mode 100644 vendor/github.com/prometheus/procfs/README.md delete mode 100644 vendor/github.com/prometheus/procfs/buddyinfo.go delete mode 100644 vendor/github.com/prometheus/procfs/doc.go delete mode 120000 vendor/github.com/prometheus/procfs/fixtures/26231/exe delete mode 120000 vendor/github.com/prometheus/procfs/fixtures/26231/fd/0 delete mode 120000 vendor/github.com/prometheus/procfs/fixtures/26231/fd/1 delete mode 120000 vendor/github.com/prometheus/procfs/fixtures/26231/fd/10 delete mode 120000 vendor/github.com/prometheus/procfs/fixtures/26231/fd/2 delete mode 120000 vendor/github.com/prometheus/procfs/fixtures/26231/fd/3 delete mode 120000 vendor/github.com/prometheus/procfs/fixtures/26231/ns/mnt delete mode 120000 vendor/github.com/prometheus/procfs/fixtures/26231/ns/net delete mode 120000 vendor/github.com/prometheus/procfs/fixtures/26232/fd/0 delete mode 120000 vendor/github.com/prometheus/procfs/fixtures/26232/fd/1 delete mode 120000 vendor/github.com/prometheus/procfs/fixtures/26232/fd/2 delete mode 120000 vendor/github.com/prometheus/procfs/fixtures/26232/fd/3 delete mode 120000 vendor/github.com/prometheus/procfs/fixtures/26232/fd/4 delete mode 120000 vendor/github.com/prometheus/procfs/fixtures/self delete mode 100644 vendor/github.com/prometheus/procfs/fs.go delete mode 100644 vendor/github.com/prometheus/procfs/internal/util/parse.go delete mode 100644 vendor/github.com/prometheus/procfs/ipvs.go delete mode 100644 vendor/github.com/prometheus/procfs/mdstat.go delete mode 100644 vendor/github.com/prometheus/procfs/mountstats.go delete mode 100644 vendor/github.com/prometheus/procfs/net_dev.go delete mode 100644 vendor/github.com/prometheus/procfs/nfs/nfs.go delete mode 100644 vendor/github.com/prometheus/procfs/nfs/parse.go delete mode 100644 vendor/github.com/prometheus/procfs/nfs/parse_nfs.go delete mode 100644 vendor/github.com/prometheus/procfs/nfs/parse_nfsd.go delete mode 100644 vendor/github.com/prometheus/procfs/proc.go delete mode 100644 vendor/github.com/prometheus/procfs/proc_io.go delete mode 100644 vendor/github.com/prometheus/procfs/proc_limits.go delete mode 100644 vendor/github.com/prometheus/procfs/proc_ns.go delete mode 100644 vendor/github.com/prometheus/procfs/proc_stat.go delete mode 100644 vendor/github.com/prometheus/procfs/stat.go delete mode 100755 vendor/github.com/prometheus/procfs/ttar delete mode 100644 vendor/github.com/prometheus/procfs/xfrm.go delete mode 100644 vendor/github.com/prometheus/procfs/xfs/parse.go delete mode 100644 vendor/github.com/prometheus/procfs/xfs/xfs.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c3da290 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea/* + diff --git a/Gopkg.lock b/Gopkg.lock deleted file mode 100644 index 1b15c95..0000000 --- a/Gopkg.lock +++ /dev/null @@ -1,69 +0,0 @@ -# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. - - -[[projects]] - branch = "master" - name = "github.com/beorn7/perks" - packages = ["quantile"] - revision = "4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9" - -[[projects]] - branch = "master" - name = "github.com/golang/protobuf" - packages = ["proto"] - revision = "925541529c1fa6821df4e44ce2723319eb2be768" - -[[projects]] - name = "github.com/matttproud/golang_protobuf_extensions" - packages = ["pbutil"] - revision = "3247c84500bff8d9fb6d579d800f20b3e091582c" - version = "v1.0.0" - -[[projects]] - branch = "master" - name = "github.com/mindprince/gonvml" - packages = ["."] - revision = "eea82dc7bb371c99a9f2b991088e267ab473b40a" - -[[projects]] - name = "github.com/prometheus/client_golang" - packages = [ - "prometheus", - "prometheus/promhttp" - ] - revision = "c5b7fccd204277076155f10851dad72b76a49317" - version = "v0.8.0" - -[[projects]] - branch = "master" - name = "github.com/prometheus/client_model" - packages = ["go"] - revision = "99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c" - -[[projects]] - branch = "master" - name = "github.com/prometheus/common" - packages = [ - "expfmt", - "internal/bitbucket.org/ww/goautoneg", - "model" - ] - revision = "89604d197083d4781071d3c65855d24ecfb0a563" - -[[projects]] - branch = "master" - name = "github.com/prometheus/procfs" - packages = [ - ".", - "internal/util", - "nfs", - "xfs" - ] - revision = "cb4147076ac75738c9a7d279075a253c0cc5acbd" - -[solve-meta] - analyzer-name = "dep" - analyzer-version = 1 - inputs-digest = "4164880afee0355bcb5dede946a616103b8849312a49d902665bba0826827fbb" - solver-name = "gps-cdcl" - solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml deleted file mode 100644 index 73b5890..0000000 --- a/Gopkg.toml +++ /dev/null @@ -1,38 +0,0 @@ -# Gopkg.toml example -# -# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md -# for detailed Gopkg.toml documentation. -# -# required = ["github.com/user/thing/cmd/thing"] -# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] -# -# [[constraint]] -# name = "github.com/user/project" -# version = "1.0.0" -# -# [[constraint]] -# name = "github.com/user/project2" -# branch = "dev" -# source = "github.com/myfork/project2" -# -# [[override]] -# name = "github.com/x/y" -# version = "2.4.0" -# -# [prune] -# non-go = false -# go-tests = true -# unused-packages = true - - -[prune] - go-tests = true - unused-packages = true - -[[constraint]] - branch = "master" - name = "github.com/mindprince/gonvml" - -[[constraint]] - name = "github.com/prometheus/client_golang" - version = "0.8.0" diff --git a/vendor/github.com/beorn7/perks/LICENSE b/vendor/github.com/beorn7/perks/LICENSE deleted file mode 100644 index 339177b..0000000 --- a/vendor/github.com/beorn7/perks/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (C) 2013 Blake Mizerany - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/beorn7/perks/quantile/exampledata.txt b/vendor/github.com/beorn7/perks/quantile/exampledata.txt deleted file mode 100644 index 1602287..0000000 --- a/vendor/github.com/beorn7/perks/quantile/exampledata.txt +++ /dev/null @@ -1,2388 +0,0 @@ -8 -5 -26 -12 -5 -235 -13 -6 -28 -30 -3 -3 -3 -3 -5 -2 -33 -7 -2 -4 -7 -12 -14 -5 -8 -3 -10 -4 -5 -3 -6 -6 -209 -20 -3 -10 -14 -3 -4 -6 -8 -5 -11 -7 -3 -2 -3 -3 -212 -5 -222 -4 -10 -10 -5 -6 -3 -8 -3 -10 -254 -220 -2 -3 -5 -24 -5 -4 -222 -7 -3 -3 -223 -8 -15 -12 -14 -14 -3 -2 -2 -3 -13 -3 -11 -4 -4 -6 -5 -7 -13 -5 -3 -5 -2 -5 -3 -5 -2 -7 -15 -17 -14 -3 -6 -6 -3 -17 -5 -4 -7 -6 -4 -4 -8 -6 -8 -3 -9 -3 -6 -3 -4 -5 -3 -3 -660 -4 -6 -10 -3 -6 -3 -2 -5 -13 -2 -4 -4 -10 -4 -8 -4 -3 -7 -9 -9 -3 -10 -37 -3 -13 -4 -12 -3 -6 -10 -8 -5 -21 -2 -3 -8 -3 -2 -3 -3 -4 -12 -2 -4 -8 -8 -4 -3 -2 -20 -1 -6 -32 -2 -11 -6 -18 -3 -8 -11 -3 -212 -3 -4 -2 -6 -7 -12 -11 -3 -2 -16 -10 -6 -4 -6 -3 -2 -7 -3 -2 -2 -2 -2 -5 -6 -4 -3 -10 -3 -4 -6 -5 -3 -4 -4 -5 -6 -4 -3 -4 -4 -5 -7 -5 -5 -3 -2 -7 -2 -4 -12 -4 -5 -6 -2 -4 -4 -8 -4 -15 -13 -7 -16 -5 -3 -23 -5 -5 -7 -3 -2 -9 -8 -7 -5 -8 -11 -4 -10 -76 -4 -47 -4 -3 -2 -7 -4 -2 -3 -37 -10 -4 -2 -20 -5 -4 -4 -10 -10 -4 -3 -7 -23 -240 -7 -13 -5 -5 -3 -3 -2 -5 -4 -2 -8 -7 -19 -2 -23 -8 -7 -2 -5 -3 -8 -3 -8 -13 -5 -5 -5 -2 -3 -23 -4 -9 -8 -4 -3 -3 -5 -220 -2 -3 -4 -6 -14 -3 -53 -6 -2 -5 -18 -6 -3 -219 -6 -5 -2 -5 -3 -6 -5 -15 -4 -3 -17 -3 -2 -4 -7 -2 -3 -3 -4 -4 -3 -2 -664 -6 -3 -23 -5 -5 -16 -5 -8 -2 -4 -2 -24 -12 -3 -2 -3 -5 -8 -3 -5 -4 -3 -14 -3 -5 -8 -2 -3 -7 -9 -4 -2 -3 -6 -8 -4 -3 -4 -6 -5 -3 -3 -6 -3 -19 -4 -4 -6 -3 -6 -3 -5 -22 -5 -4 -4 -3 -8 -11 -4 -9 -7 -6 -13 -4 -4 -4 -6 -17 -9 -3 -3 -3 -4 -3 -221 -5 -11 -3 -4 -2 -12 -6 -3 -5 -7 -5 -7 -4 -9 -7 -14 -37 -19 -217 -16 -3 -5 -2 -2 -7 -19 -7 -6 -7 -4 -24 -5 -11 -4 -7 -7 -9 -13 -3 -4 -3 -6 -28 -4 -4 -5 -5 -2 -5 -6 -4 -4 -6 -10 -5 -4 -3 -2 -3 -3 -6 -5 -5 -4 -3 -2 -3 -7 -4 -6 -18 -16 -8 -16 -4 -5 -8 -6 -9 -13 -1545 -6 -215 -6 -5 -6 -3 -45 -31 -5 -2 -2 -4 -3 -3 -2 -5 -4 -3 -5 -7 -7 -4 -5 -8 -5 -4 -749 -2 -31 -9 -11 -2 -11 -5 -4 -4 -7 -9 -11 -4 -5 -4 -7 -3 -4 -6 -2 -15 -3 -4 -3 -4 -3 -5 -2 -13 -5 -5 -3 -3 -23 -4 -4 -5 -7 -4 -13 -2 -4 -3 -4 -2 -6 -2 -7 -3 -5 -5 -3 -29 -5 -4 -4 -3 -10 -2 -3 -79 -16 -6 -6 -7 -7 -3 -5 -5 -7 -4 -3 -7 -9 -5 -6 -5 -9 -6 -3 -6 -4 -17 -2 -10 -9 -3 -6 -2 -3 -21 -22 -5 -11 -4 -2 -17 -2 -224 -2 -14 -3 -4 -4 -2 -4 -4 -4 -4 -5 -3 -4 -4 -10 -2 -6 -3 -3 -5 -7 -2 -7 -5 -6 -3 -218 -2 -2 -5 -2 -6 -3 -5 -222 -14 -6 -33 -3 -2 -5 -3 -3 -3 -9 -5 -3 -3 -2 -7 -4 -3 -4 -3 -5 -6 -5 -26 -4 -13 -9 -7 -3 -221 -3 -3 -4 -4 -4 -4 -2 -18 -5 -3 -7 -9 -6 -8 -3 -10 -3 -11 -9 -5 -4 -17 -5 -5 -6 -6 -3 -2 -4 -12 -17 -6 -7 -218 -4 -2 -4 -10 -3 -5 -15 -3 -9 -4 -3 -3 -6 -29 -3 -3 -4 -5 -5 -3 -8 -5 -6 -6 -7 -5 -3 -5 -3 -29 -2 -31 -5 -15 -24 -16 -5 -207 -4 -3 -3 -2 -15 -4 -4 -13 -5 -5 -4 -6 -10 -2 -7 -8 -4 -6 -20 -5 -3 -4 -3 -12 -12 -5 -17 -7 -3 -3 -3 -6 -10 -3 -5 -25 -80 -4 -9 -3 -2 -11 -3 -3 -2 -3 -8 -7 -5 -5 -19 -5 -3 -3 -12 -11 -2 -6 -5 -5 -5 -3 -3 -3 -4 -209 -14 -3 -2 -5 -19 -4 -4 -3 -4 -14 -5 -6 -4 -13 -9 -7 -4 -7 -10 -2 -9 -5 -7 -2 -8 -4 -6 -5 -5 -222 -8 -7 -12 -5 -216 -3 -4 -4 -6 -3 -14 -8 -7 -13 -4 -3 -3 -3 -3 -17 -5 -4 -3 -33 -6 -6 -33 -7 -5 -3 -8 -7 -5 -2 -9 -4 -2 -233 -24 -7 -4 -8 -10 -3 -4 -15 -2 -16 -3 -3 -13 -12 -7 -5 -4 -207 -4 -2 -4 -27 -15 -2 -5 -2 -25 -6 -5 -5 -6 -13 -6 -18 -6 -4 -12 -225 -10 -7 -5 -2 -2 -11 -4 -14 -21 -8 -10 -3 -5 -4 -232 -2 -5 -5 -3 -7 -17 -11 -6 -6 -23 -4 -6 -3 -5 -4 -2 -17 -3 -6 -5 -8 -3 -2 -2 -14 -9 -4 -4 -2 -5 -5 -3 -7 -6 -12 -6 -10 -3 -6 -2 -2 -19 -5 -4 -4 -9 -2 -4 -13 -3 -5 -6 -3 -6 -5 -4 -9 -6 -3 -5 -7 -3 -6 -6 -4 -3 -10 -6 -3 -221 -3 -5 -3 -6 -4 -8 -5 -3 -6 -4 -4 -2 -54 -5 -6 -11 -3 -3 -4 -4 -4 -3 -7 -3 -11 -11 -7 -10 -6 -13 -223 -213 -15 -231 -7 -3 -7 -228 -2 -3 -4 -4 -5 -6 -7 -4 -13 -3 -4 -5 -3 -6 -4 -6 -7 -2 -4 -3 -4 -3 -3 -6 -3 -7 -3 -5 -18 -5 -6 -8 -10 -3 -3 -3 -2 -4 -2 -4 -4 -5 -6 -6 -4 -10 -13 -3 -12 -5 -12 -16 -8 -4 -19 -11 -2 -4 -5 -6 -8 -5 -6 -4 -18 -10 -4 -2 -216 -6 -6 -6 -2 -4 -12 -8 -3 -11 -5 -6 -14 -5 -3 -13 -4 -5 -4 -5 -3 -28 -6 -3 -7 -219 -3 -9 -7 -3 -10 -6 -3 -4 -19 -5 -7 -11 -6 -15 -19 -4 -13 -11 -3 -7 -5 -10 -2 -8 -11 -2 -6 -4 -6 -24 -6 -3 -3 -3 -3 -6 -18 -4 -11 -4 -2 -5 -10 -8 -3 -9 -5 -3 -4 -5 -6 -2 -5 -7 -4 -4 -14 -6 -4 -4 -5 -5 -7 -2 -4 -3 -7 -3 -3 -6 -4 -5 -4 -4 -4 -3 -3 -3 -3 -8 -14 -2 -3 -5 -3 -2 -4 -5 -3 -7 -3 -3 -18 -3 -4 -4 -5 -7 -3 -3 -3 -13 -5 -4 -8 -211 -5 -5 -3 -5 -2 -5 -4 -2 -655 -6 -3 -5 -11 -2 -5 -3 -12 -9 -15 -11 -5 -12 -217 -2 -6 -17 -3 -3 -207 -5 -5 -4 -5 -9 -3 -2 -8 -5 -4 -3 -2 -5 -12 -4 -14 -5 -4 -2 -13 -5 -8 -4 -225 -4 -3 -4 -5 -4 -3 -3 -6 -23 -9 -2 -6 -7 -233 -4 -4 -6 -18 -3 -4 -6 -3 -4 -4 -2 -3 -7 -4 -13 -227 -4 -3 -5 -4 -2 -12 -9 -17 -3 -7 -14 -6 -4 -5 -21 -4 -8 -9 -2 -9 -25 -16 -3 -6 -4 -7 -8 -5 -2 -3 -5 -4 -3 -3 -5 -3 -3 -3 -2 -3 -19 -2 -4 -3 -4 -2 -3 -4 -4 -2 -4 -3 -3 -3 -2 -6 -3 -17 -5 -6 -4 -3 -13 -5 -3 -3 -3 -4 -9 -4 -2 -14 -12 -4 -5 -24 -4 -3 -37 -12 -11 -21 -3 -4 -3 -13 -4 -2 -3 -15 -4 -11 -4 -4 -3 -8 -3 -4 -4 -12 -8 -5 -3 -3 -4 -2 -220 -3 -5 -223 -3 -3 -3 -10 -3 -15 -4 -241 -9 -7 -3 -6 -6 -23 -4 -13 -7 -3 -4 -7 -4 -9 -3 -3 -4 -10 -5 -5 -1 -5 -24 -2 -4 -5 -5 -6 -14 -3 -8 -2 -3 -5 -13 -13 -3 -5 -2 -3 -15 -3 -4 -2 -10 -4 -4 -4 -5 -5 -3 -5 -3 -4 -7 -4 -27 -3 -6 -4 -15 -3 -5 -6 -6 -5 -4 -8 -3 -9 -2 -6 -3 -4 -3 -7 -4 -18 -3 -11 -3 -3 -8 -9 -7 -24 -3 -219 -7 -10 -4 -5 -9 -12 -2 -5 -4 -4 -4 -3 -3 -19 -5 -8 -16 -8 -6 -22 -3 -23 -3 -242 -9 -4 -3 -3 -5 -7 -3 -3 -5 -8 -3 -7 -5 -14 -8 -10 -3 -4 -3 -7 -4 -6 -7 -4 -10 -4 -3 -11 -3 -7 -10 -3 -13 -6 -8 -12 -10 -5 -7 -9 -3 -4 -7 -7 -10 -8 -30 -9 -19 -4 -3 -19 -15 -4 -13 -3 -215 -223 -4 -7 -4 -8 -17 -16 -3 -7 -6 -5 -5 -4 -12 -3 -7 -4 -4 -13 -4 -5 -2 -5 -6 -5 -6 -6 -7 -10 -18 -23 -9 -3 -3 -6 -5 -2 -4 -2 -7 -3 -3 -2 -5 -5 -14 -10 -224 -6 -3 -4 -3 -7 -5 -9 -3 -6 -4 -2 -5 -11 -4 -3 -3 -2 -8 -4 -7 -4 -10 -7 -3 -3 -18 -18 -17 -3 -3 -3 -4 -5 -3 -3 -4 -12 -7 -3 -11 -13 -5 -4 -7 -13 -5 -4 -11 -3 -12 -3 -6 -4 -4 -21 -4 -6 -9 -5 -3 -10 -8 -4 -6 -4 -4 -6 -5 -4 -8 -6 -4 -6 -4 -4 -5 -9 -6 -3 -4 -2 -9 -3 -18 -2 -4 -3 -13 -3 -6 -6 -8 -7 -9 -3 -2 -16 -3 -4 -6 -3 -2 -33 -22 -14 -4 -9 -12 -4 -5 -6 -3 -23 -9 -4 -3 -5 -5 -3 -4 -5 -3 -5 -3 -10 -4 -5 -5 -8 -4 -4 -6 -8 -5 -4 -3 -4 -6 -3 -3 -3 -5 -9 -12 -6 -5 -9 -3 -5 -3 -2 -2 -2 -18 -3 -2 -21 -2 -5 -4 -6 -4 -5 -10 -3 -9 -3 -2 -10 -7 -3 -6 -6 -4 -4 -8 -12 -7 -3 -7 -3 -3 -9 -3 -4 -5 -4 -4 -5 -5 -10 -15 -4 -4 -14 -6 -227 -3 -14 -5 -216 -22 -5 -4 -2 -2 -6 -3 -4 -2 -9 -9 -4 -3 -28 -13 -11 -4 -5 -3 -3 -2 -3 -3 -5 -3 -4 -3 -5 -23 -26 -3 -4 -5 -6 -4 -6 -3 -5 -5 -3 -4 -3 -2 -2 -2 -7 -14 -3 -6 -7 -17 -2 -2 -15 -14 -16 -4 -6 -7 -13 -6 -4 -5 -6 -16 -3 -3 -28 -3 -6 -15 -3 -9 -2 -4 -6 -3 -3 -22 -4 -12 -6 -7 -2 -5 -4 -10 -3 -16 -6 -9 -2 -5 -12 -7 -5 -5 -5 -5 -2 -11 -9 -17 -4 -3 -11 -7 -3 -5 -15 -4 -3 -4 -211 -8 -7 -5 -4 -7 -6 -7 -6 -3 -6 -5 -6 -5 -3 -4 -4 -26 -4 -6 -10 -4 -4 -3 -2 -3 -3 -4 -5 -9 -3 -9 -4 -4 -5 -5 -8 -2 -4 -2 -3 -8 -4 -11 -19 -5 -8 -6 -3 -5 -6 -12 -3 -2 -4 -16 -12 -3 -4 -4 -8 -6 -5 -6 -6 -219 -8 -222 -6 -16 -3 -13 -19 -5 -4 -3 -11 -6 -10 -4 -7 -7 -12 -5 -3 -3 -5 -6 -10 -3 -8 -2 -5 -4 -7 -2 -4 -4 -2 -12 -9 -6 -4 -2 -40 -2 -4 -10 -4 -223 -4 -2 -20 -6 -7 -24 -5 -4 -5 -2 -20 -16 -6 -5 -13 -2 -3 -3 -19 -3 -2 -4 -5 -6 -7 -11 -12 -5 -6 -7 -7 -3 -5 -3 -5 -3 -14 -3 -4 -4 -2 -11 -1 -7 -3 -9 -6 -11 -12 -5 -8 -6 -221 -4 -2 -12 -4 -3 -15 -4 -5 -226 -7 -218 -7 -5 -4 -5 -18 -4 -5 -9 -4 -4 -2 -9 -18 -18 -9 -5 -6 -6 -3 -3 -7 -3 -5 -4 -4 -4 -12 -3 -6 -31 -5 -4 -7 -3 -6 -5 -6 -5 -11 -2 -2 -11 -11 -6 -7 -5 -8 -7 -10 -5 -23 -7 -4 -3 -5 -34 -2 -5 -23 -7 -3 -6 -8 -4 -4 -4 -2 -5 -3 -8 -5 -4 -8 -25 -2 -3 -17 -8 -3 -4 -8 -7 -3 -15 -6 -5 -7 -21 -9 -5 -6 -6 -5 -3 -2 -3 -10 -3 -6 -3 -14 -7 -4 -4 -8 -7 -8 -2 -6 -12 -4 -213 -6 -5 -21 -8 -2 -5 -23 -3 -11 -2 -3 -6 -25 -2 -3 -6 -7 -6 -6 -4 -4 -6 -3 -17 -9 -7 -6 -4 -3 -10 -7 -2 -3 -3 -3 -11 -8 -3 -7 -6 -4 -14 -36 -3 -4 -3 -3 -22 -13 -21 -4 -2 -7 -4 -4 -17 -15 -3 -7 -11 -2 -4 -7 -6 -209 -6 -3 -2 -2 -24 -4 -9 -4 -3 -3 -3 -29 -2 -2 -4 -3 -3 -5 -4 -6 -3 -3 -2 -4 diff --git a/vendor/github.com/beorn7/perks/quantile/stream.go b/vendor/github.com/beorn7/perks/quantile/stream.go deleted file mode 100644 index f4cabd6..0000000 --- a/vendor/github.com/beorn7/perks/quantile/stream.go +++ /dev/null @@ -1,292 +0,0 @@ -// Package quantile computes approximate quantiles over an unbounded data -// stream within low memory and CPU bounds. -// -// A small amount of accuracy is traded to achieve the above properties. -// -// Multiple streams can be merged before calling Query to generate a single set -// of results. This is meaningful when the streams represent the same type of -// data. See Merge and Samples. -// -// For more detailed information about the algorithm used, see: -// -// Effective Computation of Biased Quantiles over Data Streams -// -// http://www.cs.rutgers.edu/~muthu/bquant.pdf -package quantile - -import ( - "math" - "sort" -) - -// Sample holds an observed value and meta information for compression. JSON -// tags have been added for convenience. -type Sample struct { - Value float64 `json:",string"` - Width float64 `json:",string"` - Delta float64 `json:",string"` -} - -// Samples represents a slice of samples. It implements sort.Interface. -type Samples []Sample - -func (a Samples) Len() int { return len(a) } -func (a Samples) Less(i, j int) bool { return a[i].Value < a[j].Value } -func (a Samples) Swap(i, j int) { a[i], a[j] = a[j], a[i] } - -type invariant func(s *stream, r float64) float64 - -// NewLowBiased returns an initialized Stream for low-biased quantiles -// (e.g. 0.01, 0.1, 0.5) where the needed quantiles are not known a priori, but -// error guarantees can still be given even for the lower ranks of the data -// distribution. -// -// The provided epsilon is a relative error, i.e. the true quantile of a value -// returned by a query is guaranteed to be within (1±Epsilon)*Quantile. -// -// See http://www.cs.rutgers.edu/~muthu/bquant.pdf for time, space, and error -// properties. -func NewLowBiased(epsilon float64) *Stream { - ƒ := func(s *stream, r float64) float64 { - return 2 * epsilon * r - } - return newStream(ƒ) -} - -// NewHighBiased returns an initialized Stream for high-biased quantiles -// (e.g. 0.01, 0.1, 0.5) where the needed quantiles are not known a priori, but -// error guarantees can still be given even for the higher ranks of the data -// distribution. -// -// The provided epsilon is a relative error, i.e. the true quantile of a value -// returned by a query is guaranteed to be within 1-(1±Epsilon)*(1-Quantile). -// -// See http://www.cs.rutgers.edu/~muthu/bquant.pdf for time, space, and error -// properties. -func NewHighBiased(epsilon float64) *Stream { - ƒ := func(s *stream, r float64) float64 { - return 2 * epsilon * (s.n - r) - } - return newStream(ƒ) -} - -// NewTargeted returns an initialized Stream concerned with a particular set of -// quantile values that are supplied a priori. Knowing these a priori reduces -// space and computation time. The targets map maps the desired quantiles to -// their absolute errors, i.e. the true quantile of a value returned by a query -// is guaranteed to be within (Quantile±Epsilon). -// -// See http://www.cs.rutgers.edu/~muthu/bquant.pdf for time, space, and error properties. -func NewTargeted(targets map[float64]float64) *Stream { - ƒ := func(s *stream, r float64) float64 { - var m = math.MaxFloat64 - var f float64 - for quantile, epsilon := range targets { - if quantile*s.n <= r { - f = (2 * epsilon * r) / quantile - } else { - f = (2 * epsilon * (s.n - r)) / (1 - quantile) - } - if f < m { - m = f - } - } - return m - } - return newStream(ƒ) -} - -// Stream computes quantiles for a stream of float64s. It is not thread-safe by -// design. Take care when using across multiple goroutines. -type Stream struct { - *stream - b Samples - sorted bool -} - -func newStream(ƒ invariant) *Stream { - x := &stream{ƒ: ƒ} - return &Stream{x, make(Samples, 0, 500), true} -} - -// Insert inserts v into the stream. -func (s *Stream) Insert(v float64) { - s.insert(Sample{Value: v, Width: 1}) -} - -func (s *Stream) insert(sample Sample) { - s.b = append(s.b, sample) - s.sorted = false - if len(s.b) == cap(s.b) { - s.flush() - } -} - -// Query returns the computed qth percentiles value. If s was created with -// NewTargeted, and q is not in the set of quantiles provided a priori, Query -// will return an unspecified result. -func (s *Stream) Query(q float64) float64 { - if !s.flushed() { - // Fast path when there hasn't been enough data for a flush; - // this also yields better accuracy for small sets of data. - l := len(s.b) - if l == 0 { - return 0 - } - i := int(math.Ceil(float64(l) * q)) - if i > 0 { - i -= 1 - } - s.maybeSort() - return s.b[i].Value - } - s.flush() - return s.stream.query(q) -} - -// Merge merges samples into the underlying streams samples. This is handy when -// merging multiple streams from separate threads, database shards, etc. -// -// ATTENTION: This method is broken and does not yield correct results. The -// underlying algorithm is not capable of merging streams correctly. -func (s *Stream) Merge(samples Samples) { - sort.Sort(samples) - s.stream.merge(samples) -} - -// Reset reinitializes and clears the list reusing the samples buffer memory. -func (s *Stream) Reset() { - s.stream.reset() - s.b = s.b[:0] -} - -// Samples returns stream samples held by s. -func (s *Stream) Samples() Samples { - if !s.flushed() { - return s.b - } - s.flush() - return s.stream.samples() -} - -// Count returns the total number of samples observed in the stream -// since initialization. -func (s *Stream) Count() int { - return len(s.b) + s.stream.count() -} - -func (s *Stream) flush() { - s.maybeSort() - s.stream.merge(s.b) - s.b = s.b[:0] -} - -func (s *Stream) maybeSort() { - if !s.sorted { - s.sorted = true - sort.Sort(s.b) - } -} - -func (s *Stream) flushed() bool { - return len(s.stream.l) > 0 -} - -type stream struct { - n float64 - l []Sample - ƒ invariant -} - -func (s *stream) reset() { - s.l = s.l[:0] - s.n = 0 -} - -func (s *stream) insert(v float64) { - s.merge(Samples{{v, 1, 0}}) -} - -func (s *stream) merge(samples Samples) { - // TODO(beorn7): This tries to merge not only individual samples, but - // whole summaries. The paper doesn't mention merging summaries at - // all. Unittests show that the merging is inaccurate. Find out how to - // do merges properly. - var r float64 - i := 0 - for _, sample := range samples { - for ; i < len(s.l); i++ { - c := s.l[i] - if c.Value > sample.Value { - // Insert at position i. - s.l = append(s.l, Sample{}) - copy(s.l[i+1:], s.l[i:]) - s.l[i] = Sample{ - sample.Value, - sample.Width, - math.Max(sample.Delta, math.Floor(s.ƒ(s, r))-1), - // TODO(beorn7): How to calculate delta correctly? - } - i++ - goto inserted - } - r += c.Width - } - s.l = append(s.l, Sample{sample.Value, sample.Width, 0}) - i++ - inserted: - s.n += sample.Width - r += sample.Width - } - s.compress() -} - -func (s *stream) count() int { - return int(s.n) -} - -func (s *stream) query(q float64) float64 { - t := math.Ceil(q * s.n) - t += math.Ceil(s.ƒ(s, t) / 2) - p := s.l[0] - var r float64 - for _, c := range s.l[1:] { - r += p.Width - if r+c.Width+c.Delta > t { - return p.Value - } - p = c - } - return p.Value -} - -func (s *stream) compress() { - if len(s.l) < 2 { - return - } - x := s.l[len(s.l)-1] - xi := len(s.l) - 1 - r := s.n - 1 - x.Width - - for i := len(s.l) - 2; i >= 0; i-- { - c := s.l[i] - if c.Width+x.Width+x.Delta <= s.ƒ(s, r) { - x.Width += c.Width - s.l[xi] = x - // Remove element at i. - copy(s.l[i:], s.l[i+1:]) - s.l = s.l[:len(s.l)-1] - xi -= 1 - } else { - x = c - xi = i - } - r -= c.Width - } -} - -func (s *stream) samples() Samples { - samples := make(Samples, len(s.l)) - copy(samples, s.l) - return samples -} diff --git a/vendor/github.com/golang/protobuf/AUTHORS b/vendor/github.com/golang/protobuf/AUTHORS deleted file mode 100644 index 15167cd..0000000 --- a/vendor/github.com/golang/protobuf/AUTHORS +++ /dev/null @@ -1,3 +0,0 @@ -# This source code refers to The Go Authors for copyright purposes. -# The master list of authors is in the main Go distribution, -# visible at http://tip.golang.org/AUTHORS. diff --git a/vendor/github.com/golang/protobuf/CONTRIBUTORS b/vendor/github.com/golang/protobuf/CONTRIBUTORS deleted file mode 100644 index 1c4577e..0000000 --- a/vendor/github.com/golang/protobuf/CONTRIBUTORS +++ /dev/null @@ -1,3 +0,0 @@ -# This source code was written by the Go contributors. -# The master list of contributors is in the main Go distribution, -# visible at http://tip.golang.org/CONTRIBUTORS. diff --git a/vendor/github.com/golang/protobuf/LICENSE b/vendor/github.com/golang/protobuf/LICENSE deleted file mode 100644 index 1b1b192..0000000 --- a/vendor/github.com/golang/protobuf/LICENSE +++ /dev/null @@ -1,31 +0,0 @@ -Go support for Protocol Buffers - Google's data interchange format - -Copyright 2010 The Go Authors. All rights reserved. -https://github.com/golang/protobuf - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - diff --git a/vendor/github.com/golang/protobuf/proto/Makefile b/vendor/github.com/golang/protobuf/proto/Makefile deleted file mode 100644 index e2e0651..0000000 --- a/vendor/github.com/golang/protobuf/proto/Makefile +++ /dev/null @@ -1,43 +0,0 @@ -# Go support for Protocol Buffers - Google's data interchange format -# -# Copyright 2010 The Go Authors. All rights reserved. -# https://github.com/golang/protobuf -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -install: - go install - -test: install generate-test-pbs - go test - - -generate-test-pbs: - make install - make -C testdata - protoc --go_out=Mtestdata/test.proto=github.com/golang/protobuf/proto/testdata,Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any:. proto3_proto/proto3.proto - make diff --git a/vendor/github.com/golang/protobuf/proto/clone.go b/vendor/github.com/golang/protobuf/proto/clone.go deleted file mode 100644 index e392575..0000000 --- a/vendor/github.com/golang/protobuf/proto/clone.go +++ /dev/null @@ -1,229 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2011 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Protocol buffer deep copy and merge. -// TODO: RawMessage. - -package proto - -import ( - "log" - "reflect" - "strings" -) - -// Clone returns a deep copy of a protocol buffer. -func Clone(pb Message) Message { - in := reflect.ValueOf(pb) - if in.IsNil() { - return pb - } - - out := reflect.New(in.Type().Elem()) - // out is empty so a merge is a deep copy. - mergeStruct(out.Elem(), in.Elem()) - return out.Interface().(Message) -} - -// Merge merges src into dst. -// Required and optional fields that are set in src will be set to that value in dst. -// Elements of repeated fields will be appended. -// Merge panics if src and dst are not the same type, or if dst is nil. -func Merge(dst, src Message) { - in := reflect.ValueOf(src) - out := reflect.ValueOf(dst) - if out.IsNil() { - panic("proto: nil destination") - } - if in.Type() != out.Type() { - // Explicit test prior to mergeStruct so that mistyped nils will fail - panic("proto: type mismatch") - } - if in.IsNil() { - // Merging nil into non-nil is a quiet no-op - return - } - mergeStruct(out.Elem(), in.Elem()) -} - -func mergeStruct(out, in reflect.Value) { - sprop := GetProperties(in.Type()) - for i := 0; i < in.NumField(); i++ { - f := in.Type().Field(i) - if strings.HasPrefix(f.Name, "XXX_") { - continue - } - mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i]) - } - - if emIn, ok := extendable(in.Addr().Interface()); ok { - emOut, _ := extendable(out.Addr().Interface()) - mIn, muIn := emIn.extensionsRead() - if mIn != nil { - mOut := emOut.extensionsWrite() - muIn.Lock() - mergeExtension(mOut, mIn) - muIn.Unlock() - } - } - - uf := in.FieldByName("XXX_unrecognized") - if !uf.IsValid() { - return - } - uin := uf.Bytes() - if len(uin) > 0 { - out.FieldByName("XXX_unrecognized").SetBytes(append([]byte(nil), uin...)) - } -} - -// mergeAny performs a merge between two values of the same type. -// viaPtr indicates whether the values were indirected through a pointer (implying proto2). -// prop is set if this is a struct field (it may be nil). -func mergeAny(out, in reflect.Value, viaPtr bool, prop *Properties) { - if in.Type() == protoMessageType { - if !in.IsNil() { - if out.IsNil() { - out.Set(reflect.ValueOf(Clone(in.Interface().(Message)))) - } else { - Merge(out.Interface().(Message), in.Interface().(Message)) - } - } - return - } - switch in.Kind() { - case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, - reflect.String, reflect.Uint32, reflect.Uint64: - if !viaPtr && isProto3Zero(in) { - return - } - out.Set(in) - case reflect.Interface: - // Probably a oneof field; copy non-nil values. - if in.IsNil() { - return - } - // Allocate destination if it is not set, or set to a different type. - // Otherwise we will merge as normal. - if out.IsNil() || out.Elem().Type() != in.Elem().Type() { - out.Set(reflect.New(in.Elem().Elem().Type())) // interface -> *T -> T -> new(T) - } - mergeAny(out.Elem(), in.Elem(), false, nil) - case reflect.Map: - if in.Len() == 0 { - return - } - if out.IsNil() { - out.Set(reflect.MakeMap(in.Type())) - } - // For maps with value types of *T or []byte we need to deep copy each value. - elemKind := in.Type().Elem().Kind() - for _, key := range in.MapKeys() { - var val reflect.Value - switch elemKind { - case reflect.Ptr: - val = reflect.New(in.Type().Elem().Elem()) - mergeAny(val, in.MapIndex(key), false, nil) - case reflect.Slice: - val = in.MapIndex(key) - val = reflect.ValueOf(append([]byte{}, val.Bytes()...)) - default: - val = in.MapIndex(key) - } - out.SetMapIndex(key, val) - } - case reflect.Ptr: - if in.IsNil() { - return - } - if out.IsNil() { - out.Set(reflect.New(in.Elem().Type())) - } - mergeAny(out.Elem(), in.Elem(), true, nil) - case reflect.Slice: - if in.IsNil() { - return - } - if in.Type().Elem().Kind() == reflect.Uint8 { - // []byte is a scalar bytes field, not a repeated field. - - // Edge case: if this is in a proto3 message, a zero length - // bytes field is considered the zero value, and should not - // be merged. - if prop != nil && prop.proto3 && in.Len() == 0 { - return - } - - // Make a deep copy. - // Append to []byte{} instead of []byte(nil) so that we never end up - // with a nil result. - out.SetBytes(append([]byte{}, in.Bytes()...)) - return - } - n := in.Len() - if out.IsNil() { - out.Set(reflect.MakeSlice(in.Type(), 0, n)) - } - switch in.Type().Elem().Kind() { - case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, - reflect.String, reflect.Uint32, reflect.Uint64: - out.Set(reflect.AppendSlice(out, in)) - default: - for i := 0; i < n; i++ { - x := reflect.Indirect(reflect.New(in.Type().Elem())) - mergeAny(x, in.Index(i), false, nil) - out.Set(reflect.Append(out, x)) - } - } - case reflect.Struct: - mergeStruct(out, in) - default: - // unknown type, so not a protocol buffer - log.Printf("proto: don't know how to copy %v", in) - } -} - -func mergeExtension(out, in map[int32]Extension) { - for extNum, eIn := range in { - eOut := Extension{desc: eIn.desc} - if eIn.value != nil { - v := reflect.New(reflect.TypeOf(eIn.value)).Elem() - mergeAny(v, reflect.ValueOf(eIn.value), false, nil) - eOut.value = v.Interface() - } - if eIn.enc != nil { - eOut.enc = make([]byte, len(eIn.enc)) - copy(eOut.enc, eIn.enc) - } - - out[extNum] = eOut - } -} diff --git a/vendor/github.com/golang/protobuf/proto/decode.go b/vendor/github.com/golang/protobuf/proto/decode.go deleted file mode 100644 index aa20729..0000000 --- a/vendor/github.com/golang/protobuf/proto/decode.go +++ /dev/null @@ -1,970 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -/* - * Routines for decoding protocol buffer data to construct in-memory representations. - */ - -import ( - "errors" - "fmt" - "io" - "os" - "reflect" -) - -// errOverflow is returned when an integer is too large to be represented. -var errOverflow = errors.New("proto: integer overflow") - -// ErrInternalBadWireType is returned by generated code when an incorrect -// wire type is encountered. It does not get returned to user code. -var ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof") - -// The fundamental decoders that interpret bytes on the wire. -// Those that take integer types all return uint64 and are -// therefore of type valueDecoder. - -// DecodeVarint reads a varint-encoded integer from the slice. -// It returns the integer and the number of bytes consumed, or -// zero if there is not enough. -// This is the format for the -// int32, int64, uint32, uint64, bool, and enum -// protocol buffer types. -func DecodeVarint(buf []byte) (x uint64, n int) { - for shift := uint(0); shift < 64; shift += 7 { - if n >= len(buf) { - return 0, 0 - } - b := uint64(buf[n]) - n++ - x |= (b & 0x7F) << shift - if (b & 0x80) == 0 { - return x, n - } - } - - // The number is too large to represent in a 64-bit value. - return 0, 0 -} - -func (p *Buffer) decodeVarintSlow() (x uint64, err error) { - i := p.index - l := len(p.buf) - - for shift := uint(0); shift < 64; shift += 7 { - if i >= l { - err = io.ErrUnexpectedEOF - return - } - b := p.buf[i] - i++ - x |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - p.index = i - return - } - } - - // The number is too large to represent in a 64-bit value. - err = errOverflow - return -} - -// DecodeVarint reads a varint-encoded integer from the Buffer. -// This is the format for the -// int32, int64, uint32, uint64, bool, and enum -// protocol buffer types. -func (p *Buffer) DecodeVarint() (x uint64, err error) { - i := p.index - buf := p.buf - - if i >= len(buf) { - return 0, io.ErrUnexpectedEOF - } else if buf[i] < 0x80 { - p.index++ - return uint64(buf[i]), nil - } else if len(buf)-i < 10 { - return p.decodeVarintSlow() - } - - var b uint64 - // we already checked the first byte - x = uint64(buf[i]) - 0x80 - i++ - - b = uint64(buf[i]) - i++ - x += b << 7 - if b&0x80 == 0 { - goto done - } - x -= 0x80 << 7 - - b = uint64(buf[i]) - i++ - x += b << 14 - if b&0x80 == 0 { - goto done - } - x -= 0x80 << 14 - - b = uint64(buf[i]) - i++ - x += b << 21 - if b&0x80 == 0 { - goto done - } - x -= 0x80 << 21 - - b = uint64(buf[i]) - i++ - x += b << 28 - if b&0x80 == 0 { - goto done - } - x -= 0x80 << 28 - - b = uint64(buf[i]) - i++ - x += b << 35 - if b&0x80 == 0 { - goto done - } - x -= 0x80 << 35 - - b = uint64(buf[i]) - i++ - x += b << 42 - if b&0x80 == 0 { - goto done - } - x -= 0x80 << 42 - - b = uint64(buf[i]) - i++ - x += b << 49 - if b&0x80 == 0 { - goto done - } - x -= 0x80 << 49 - - b = uint64(buf[i]) - i++ - x += b << 56 - if b&0x80 == 0 { - goto done - } - x -= 0x80 << 56 - - b = uint64(buf[i]) - i++ - x += b << 63 - if b&0x80 == 0 { - goto done - } - // x -= 0x80 << 63 // Always zero. - - return 0, errOverflow - -done: - p.index = i - return x, nil -} - -// DecodeFixed64 reads a 64-bit integer from the Buffer. -// This is the format for the -// fixed64, sfixed64, and double protocol buffer types. -func (p *Buffer) DecodeFixed64() (x uint64, err error) { - // x, err already 0 - i := p.index + 8 - if i < 0 || i > len(p.buf) { - err = io.ErrUnexpectedEOF - return - } - p.index = i - - x = uint64(p.buf[i-8]) - x |= uint64(p.buf[i-7]) << 8 - x |= uint64(p.buf[i-6]) << 16 - x |= uint64(p.buf[i-5]) << 24 - x |= uint64(p.buf[i-4]) << 32 - x |= uint64(p.buf[i-3]) << 40 - x |= uint64(p.buf[i-2]) << 48 - x |= uint64(p.buf[i-1]) << 56 - return -} - -// DecodeFixed32 reads a 32-bit integer from the Buffer. -// This is the format for the -// fixed32, sfixed32, and float protocol buffer types. -func (p *Buffer) DecodeFixed32() (x uint64, err error) { - // x, err already 0 - i := p.index + 4 - if i < 0 || i > len(p.buf) { - err = io.ErrUnexpectedEOF - return - } - p.index = i - - x = uint64(p.buf[i-4]) - x |= uint64(p.buf[i-3]) << 8 - x |= uint64(p.buf[i-2]) << 16 - x |= uint64(p.buf[i-1]) << 24 - return -} - -// DecodeZigzag64 reads a zigzag-encoded 64-bit integer -// from the Buffer. -// This is the format used for the sint64 protocol buffer type. -func (p *Buffer) DecodeZigzag64() (x uint64, err error) { - x, err = p.DecodeVarint() - if err != nil { - return - } - x = (x >> 1) ^ uint64((int64(x&1)<<63)>>63) - return -} - -// DecodeZigzag32 reads a zigzag-encoded 32-bit integer -// from the Buffer. -// This is the format used for the sint32 protocol buffer type. -func (p *Buffer) DecodeZigzag32() (x uint64, err error) { - x, err = p.DecodeVarint() - if err != nil { - return - } - x = uint64((uint32(x) >> 1) ^ uint32((int32(x&1)<<31)>>31)) - return -} - -// These are not ValueDecoders: they produce an array of bytes or a string. -// bytes, embedded messages - -// DecodeRawBytes reads a count-delimited byte buffer from the Buffer. -// This is the format used for the bytes protocol buffer -// type and for embedded messages. -func (p *Buffer) DecodeRawBytes(alloc bool) (buf []byte, err error) { - n, err := p.DecodeVarint() - if err != nil { - return nil, err - } - - nb := int(n) - if nb < 0 { - return nil, fmt.Errorf("proto: bad byte length %d", nb) - } - end := p.index + nb - if end < p.index || end > len(p.buf) { - return nil, io.ErrUnexpectedEOF - } - - if !alloc { - // todo: check if can get more uses of alloc=false - buf = p.buf[p.index:end] - p.index += nb - return - } - - buf = make([]byte, nb) - copy(buf, p.buf[p.index:]) - p.index += nb - return -} - -// DecodeStringBytes reads an encoded string from the Buffer. -// This is the format used for the proto2 string type. -func (p *Buffer) DecodeStringBytes() (s string, err error) { - buf, err := p.DecodeRawBytes(false) - if err != nil { - return - } - return string(buf), nil -} - -// Skip the next item in the buffer. Its wire type is decoded and presented as an argument. -// If the protocol buffer has extensions, and the field matches, add it as an extension. -// Otherwise, if the XXX_unrecognized field exists, append the skipped data there. -func (o *Buffer) skipAndSave(t reflect.Type, tag, wire int, base structPointer, unrecField field) error { - oi := o.index - - err := o.skip(t, tag, wire) - if err != nil { - return err - } - - if !unrecField.IsValid() { - return nil - } - - ptr := structPointer_Bytes(base, unrecField) - - // Add the skipped field to struct field - obuf := o.buf - - o.buf = *ptr - o.EncodeVarint(uint64(tag<<3 | wire)) - *ptr = append(o.buf, obuf[oi:o.index]...) - - o.buf = obuf - - return nil -} - -// Skip the next item in the buffer. Its wire type is decoded and presented as an argument. -func (o *Buffer) skip(t reflect.Type, tag, wire int) error { - - var u uint64 - var err error - - switch wire { - case WireVarint: - _, err = o.DecodeVarint() - case WireFixed64: - _, err = o.DecodeFixed64() - case WireBytes: - _, err = o.DecodeRawBytes(false) - case WireFixed32: - _, err = o.DecodeFixed32() - case WireStartGroup: - for { - u, err = o.DecodeVarint() - if err != nil { - break - } - fwire := int(u & 0x7) - if fwire == WireEndGroup { - break - } - ftag := int(u >> 3) - err = o.skip(t, ftag, fwire) - if err != nil { - break - } - } - default: - err = fmt.Errorf("proto: can't skip unknown wire type %d for %s", wire, t) - } - return err -} - -// Unmarshaler is the interface representing objects that can -// unmarshal themselves. The method should reset the receiver before -// decoding starts. The argument points to data that may be -// overwritten, so implementations should not keep references to the -// buffer. -type Unmarshaler interface { - Unmarshal([]byte) error -} - -// Unmarshal parses the protocol buffer representation in buf and places the -// decoded result in pb. If the struct underlying pb does not match -// the data in buf, the results can be unpredictable. -// -// Unmarshal resets pb before starting to unmarshal, so any -// existing data in pb is always removed. Use UnmarshalMerge -// to preserve and append to existing data. -func Unmarshal(buf []byte, pb Message) error { - pb.Reset() - return UnmarshalMerge(buf, pb) -} - -// UnmarshalMerge parses the protocol buffer representation in buf and -// writes the decoded result to pb. If the struct underlying pb does not match -// the data in buf, the results can be unpredictable. -// -// UnmarshalMerge merges into existing data in pb. -// Most code should use Unmarshal instead. -func UnmarshalMerge(buf []byte, pb Message) error { - // If the object can unmarshal itself, let it. - if u, ok := pb.(Unmarshaler); ok { - return u.Unmarshal(buf) - } - return NewBuffer(buf).Unmarshal(pb) -} - -// DecodeMessage reads a count-delimited message from the Buffer. -func (p *Buffer) DecodeMessage(pb Message) error { - enc, err := p.DecodeRawBytes(false) - if err != nil { - return err - } - return NewBuffer(enc).Unmarshal(pb) -} - -// DecodeGroup reads a tag-delimited group from the Buffer. -func (p *Buffer) DecodeGroup(pb Message) error { - typ, base, err := getbase(pb) - if err != nil { - return err - } - return p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), true, base) -} - -// Unmarshal parses the protocol buffer representation in the -// Buffer and places the decoded result in pb. If the struct -// underlying pb does not match the data in the buffer, the results can be -// unpredictable. -// -// Unlike proto.Unmarshal, this does not reset pb before starting to unmarshal. -func (p *Buffer) Unmarshal(pb Message) error { - // If the object can unmarshal itself, let it. - if u, ok := pb.(Unmarshaler); ok { - err := u.Unmarshal(p.buf[p.index:]) - p.index = len(p.buf) - return err - } - - typ, base, err := getbase(pb) - if err != nil { - return err - } - - err = p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), false, base) - - if collectStats { - stats.Decode++ - } - - return err -} - -// unmarshalType does the work of unmarshaling a structure. -func (o *Buffer) unmarshalType(st reflect.Type, prop *StructProperties, is_group bool, base structPointer) error { - var state errorState - required, reqFields := prop.reqCount, uint64(0) - - var err error - for err == nil && o.index < len(o.buf) { - oi := o.index - var u uint64 - u, err = o.DecodeVarint() - if err != nil { - break - } - wire := int(u & 0x7) - if wire == WireEndGroup { - if is_group { - if required > 0 { - // Not enough information to determine the exact field. - // (See below.) - return &RequiredNotSetError{"{Unknown}"} - } - return nil // input is satisfied - } - return fmt.Errorf("proto: %s: wiretype end group for non-group", st) - } - tag := int(u >> 3) - if tag <= 0 { - return fmt.Errorf("proto: %s: illegal tag %d (wire type %d)", st, tag, wire) - } - fieldnum, ok := prop.decoderTags.get(tag) - if !ok { - // Maybe it's an extension? - if prop.extendable { - if e, _ := extendable(structPointer_Interface(base, st)); isExtensionField(e, int32(tag)) { - if err = o.skip(st, tag, wire); err == nil { - extmap := e.extensionsWrite() - ext := extmap[int32(tag)] // may be missing - ext.enc = append(ext.enc, o.buf[oi:o.index]...) - extmap[int32(tag)] = ext - } - continue - } - } - // Maybe it's a oneof? - if prop.oneofUnmarshaler != nil { - m := structPointer_Interface(base, st).(Message) - // First return value indicates whether tag is a oneof field. - ok, err = prop.oneofUnmarshaler(m, tag, wire, o) - if err == ErrInternalBadWireType { - // Map the error to something more descriptive. - // Do the formatting here to save generated code space. - err = fmt.Errorf("bad wiretype for oneof field in %T", m) - } - if ok { - continue - } - } - err = o.skipAndSave(st, tag, wire, base, prop.unrecField) - continue - } - p := prop.Prop[fieldnum] - - if p.dec == nil { - fmt.Fprintf(os.Stderr, "proto: no protobuf decoder for %s.%s\n", st, st.Field(fieldnum).Name) - continue - } - dec := p.dec - if wire != WireStartGroup && wire != p.WireType { - if wire == WireBytes && p.packedDec != nil { - // a packable field - dec = p.packedDec - } else { - err = fmt.Errorf("proto: bad wiretype for field %s.%s: got wiretype %d, want %d", st, st.Field(fieldnum).Name, wire, p.WireType) - continue - } - } - decErr := dec(o, p, base) - if decErr != nil && !state.shouldContinue(decErr, p) { - err = decErr - } - if err == nil && p.Required { - // Successfully decoded a required field. - if tag <= 64 { - // use bitmap for fields 1-64 to catch field reuse. - var mask uint64 = 1 << uint64(tag-1) - if reqFields&mask == 0 { - // new required field - reqFields |= mask - required-- - } - } else { - // This is imprecise. It can be fooled by a required field - // with a tag > 64 that is encoded twice; that's very rare. - // A fully correct implementation would require allocating - // a data structure, which we would like to avoid. - required-- - } - } - } - if err == nil { - if is_group { - return io.ErrUnexpectedEOF - } - if state.err != nil { - return state.err - } - if required > 0 { - // Not enough information to determine the exact field. If we use extra - // CPU, we could determine the field only if the missing required field - // has a tag <= 64 and we check reqFields. - return &RequiredNotSetError{"{Unknown}"} - } - } - return err -} - -// Individual type decoders -// For each, -// u is the decoded value, -// v is a pointer to the field (pointer) in the struct - -// Sizes of the pools to allocate inside the Buffer. -// The goal is modest amortization and allocation -// on at least 16-byte boundaries. -const ( - boolPoolSize = 16 - uint32PoolSize = 8 - uint64PoolSize = 4 -) - -// Decode a bool. -func (o *Buffer) dec_bool(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - if len(o.bools) == 0 { - o.bools = make([]bool, boolPoolSize) - } - o.bools[0] = u != 0 - *structPointer_Bool(base, p.field) = &o.bools[0] - o.bools = o.bools[1:] - return nil -} - -func (o *Buffer) dec_proto3_bool(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - *structPointer_BoolVal(base, p.field) = u != 0 - return nil -} - -// Decode an int32. -func (o *Buffer) dec_int32(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - word32_Set(structPointer_Word32(base, p.field), o, uint32(u)) - return nil -} - -func (o *Buffer) dec_proto3_int32(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - word32Val_Set(structPointer_Word32Val(base, p.field), uint32(u)) - return nil -} - -// Decode an int64. -func (o *Buffer) dec_int64(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - word64_Set(structPointer_Word64(base, p.field), o, u) - return nil -} - -func (o *Buffer) dec_proto3_int64(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - word64Val_Set(structPointer_Word64Val(base, p.field), o, u) - return nil -} - -// Decode a string. -func (o *Buffer) dec_string(p *Properties, base structPointer) error { - s, err := o.DecodeStringBytes() - if err != nil { - return err - } - *structPointer_String(base, p.field) = &s - return nil -} - -func (o *Buffer) dec_proto3_string(p *Properties, base structPointer) error { - s, err := o.DecodeStringBytes() - if err != nil { - return err - } - *structPointer_StringVal(base, p.field) = s - return nil -} - -// Decode a slice of bytes ([]byte). -func (o *Buffer) dec_slice_byte(p *Properties, base structPointer) error { - b, err := o.DecodeRawBytes(true) - if err != nil { - return err - } - *structPointer_Bytes(base, p.field) = b - return nil -} - -// Decode a slice of bools ([]bool). -func (o *Buffer) dec_slice_bool(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - v := structPointer_BoolSlice(base, p.field) - *v = append(*v, u != 0) - return nil -} - -// Decode a slice of bools ([]bool) in packed format. -func (o *Buffer) dec_slice_packed_bool(p *Properties, base structPointer) error { - v := structPointer_BoolSlice(base, p.field) - - nn, err := o.DecodeVarint() - if err != nil { - return err - } - nb := int(nn) // number of bytes of encoded bools - fin := o.index + nb - if fin < o.index { - return errOverflow - } - - y := *v - for o.index < fin { - u, err := p.valDec(o) - if err != nil { - return err - } - y = append(y, u != 0) - } - - *v = y - return nil -} - -// Decode a slice of int32s ([]int32). -func (o *Buffer) dec_slice_int32(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - structPointer_Word32Slice(base, p.field).Append(uint32(u)) - return nil -} - -// Decode a slice of int32s ([]int32) in packed format. -func (o *Buffer) dec_slice_packed_int32(p *Properties, base structPointer) error { - v := structPointer_Word32Slice(base, p.field) - - nn, err := o.DecodeVarint() - if err != nil { - return err - } - nb := int(nn) // number of bytes of encoded int32s - - fin := o.index + nb - if fin < o.index { - return errOverflow - } - for o.index < fin { - u, err := p.valDec(o) - if err != nil { - return err - } - v.Append(uint32(u)) - } - return nil -} - -// Decode a slice of int64s ([]int64). -func (o *Buffer) dec_slice_int64(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - - structPointer_Word64Slice(base, p.field).Append(u) - return nil -} - -// Decode a slice of int64s ([]int64) in packed format. -func (o *Buffer) dec_slice_packed_int64(p *Properties, base structPointer) error { - v := structPointer_Word64Slice(base, p.field) - - nn, err := o.DecodeVarint() - if err != nil { - return err - } - nb := int(nn) // number of bytes of encoded int64s - - fin := o.index + nb - if fin < o.index { - return errOverflow - } - for o.index < fin { - u, err := p.valDec(o) - if err != nil { - return err - } - v.Append(u) - } - return nil -} - -// Decode a slice of strings ([]string). -func (o *Buffer) dec_slice_string(p *Properties, base structPointer) error { - s, err := o.DecodeStringBytes() - if err != nil { - return err - } - v := structPointer_StringSlice(base, p.field) - *v = append(*v, s) - return nil -} - -// Decode a slice of slice of bytes ([][]byte). -func (o *Buffer) dec_slice_slice_byte(p *Properties, base structPointer) error { - b, err := o.DecodeRawBytes(true) - if err != nil { - return err - } - v := structPointer_BytesSlice(base, p.field) - *v = append(*v, b) - return nil -} - -// Decode a map field. -func (o *Buffer) dec_new_map(p *Properties, base structPointer) error { - raw, err := o.DecodeRawBytes(false) - if err != nil { - return err - } - oi := o.index // index at the end of this map entry - o.index -= len(raw) // move buffer back to start of map entry - - mptr := structPointer_NewAt(base, p.field, p.mtype) // *map[K]V - if mptr.Elem().IsNil() { - mptr.Elem().Set(reflect.MakeMap(mptr.Type().Elem())) - } - v := mptr.Elem() // map[K]V - - // Prepare addressable doubly-indirect placeholders for the key and value types. - // See enc_new_map for why. - keyptr := reflect.New(reflect.PtrTo(p.mtype.Key())).Elem() // addressable *K - keybase := toStructPointer(keyptr.Addr()) // **K - - var valbase structPointer - var valptr reflect.Value - switch p.mtype.Elem().Kind() { - case reflect.Slice: - // []byte - var dummy []byte - valptr = reflect.ValueOf(&dummy) // *[]byte - valbase = toStructPointer(valptr) // *[]byte - case reflect.Ptr: - // message; valptr is **Msg; need to allocate the intermediate pointer - valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V - valptr.Set(reflect.New(valptr.Type().Elem())) - valbase = toStructPointer(valptr) - default: - // everything else - valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V - valbase = toStructPointer(valptr.Addr()) // **V - } - - // Decode. - // This parses a restricted wire format, namely the encoding of a message - // with two fields. See enc_new_map for the format. - for o.index < oi { - // tagcode for key and value properties are always a single byte - // because they have tags 1 and 2. - tagcode := o.buf[o.index] - o.index++ - switch tagcode { - case p.mkeyprop.tagcode[0]: - if err := p.mkeyprop.dec(o, p.mkeyprop, keybase); err != nil { - return err - } - case p.mvalprop.tagcode[0]: - if err := p.mvalprop.dec(o, p.mvalprop, valbase); err != nil { - return err - } - default: - // TODO: Should we silently skip this instead? - return fmt.Errorf("proto: bad map data tag %d", raw[0]) - } - } - keyelem, valelem := keyptr.Elem(), valptr.Elem() - if !keyelem.IsValid() { - keyelem = reflect.Zero(p.mtype.Key()) - } - if !valelem.IsValid() { - valelem = reflect.Zero(p.mtype.Elem()) - } - - v.SetMapIndex(keyelem, valelem) - return nil -} - -// Decode a group. -func (o *Buffer) dec_struct_group(p *Properties, base structPointer) error { - bas := structPointer_GetStructPointer(base, p.field) - if structPointer_IsNil(bas) { - // allocate new nested message - bas = toStructPointer(reflect.New(p.stype)) - structPointer_SetStructPointer(base, p.field, bas) - } - return o.unmarshalType(p.stype, p.sprop, true, bas) -} - -// Decode an embedded message. -func (o *Buffer) dec_struct_message(p *Properties, base structPointer) (err error) { - raw, e := o.DecodeRawBytes(false) - if e != nil { - return e - } - - bas := structPointer_GetStructPointer(base, p.field) - if structPointer_IsNil(bas) { - // allocate new nested message - bas = toStructPointer(reflect.New(p.stype)) - structPointer_SetStructPointer(base, p.field, bas) - } - - // If the object can unmarshal itself, let it. - if p.isUnmarshaler { - iv := structPointer_Interface(bas, p.stype) - return iv.(Unmarshaler).Unmarshal(raw) - } - - obuf := o.buf - oi := o.index - o.buf = raw - o.index = 0 - - err = o.unmarshalType(p.stype, p.sprop, false, bas) - o.buf = obuf - o.index = oi - - return err -} - -// Decode a slice of embedded messages. -func (o *Buffer) dec_slice_struct_message(p *Properties, base structPointer) error { - return o.dec_slice_struct(p, false, base) -} - -// Decode a slice of embedded groups. -func (o *Buffer) dec_slice_struct_group(p *Properties, base structPointer) error { - return o.dec_slice_struct(p, true, base) -} - -// Decode a slice of structs ([]*struct). -func (o *Buffer) dec_slice_struct(p *Properties, is_group bool, base structPointer) error { - v := reflect.New(p.stype) - bas := toStructPointer(v) - structPointer_StructPointerSlice(base, p.field).Append(bas) - - if is_group { - err := o.unmarshalType(p.stype, p.sprop, is_group, bas) - return err - } - - raw, err := o.DecodeRawBytes(false) - if err != nil { - return err - } - - // If the object can unmarshal itself, let it. - if p.isUnmarshaler { - iv := v.Interface() - return iv.(Unmarshaler).Unmarshal(raw) - } - - obuf := o.buf - oi := o.index - o.buf = raw - o.index = 0 - - err = o.unmarshalType(p.stype, p.sprop, is_group, bas) - - o.buf = obuf - o.index = oi - - return err -} diff --git a/vendor/github.com/golang/protobuf/proto/discard.go b/vendor/github.com/golang/protobuf/proto/discard.go deleted file mode 100644 index bd0e3bb..0000000 --- a/vendor/github.com/golang/protobuf/proto/discard.go +++ /dev/null @@ -1,151 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2017 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -import ( - "fmt" - "reflect" - "strings" -) - -// DiscardUnknown recursively discards all unknown fields from this message -// and all embedded messages. -// -// When unmarshaling a message with unrecognized fields, the tags and values -// of such fields are preserved in the Message. This allows a later call to -// marshal to be able to produce a message that continues to have those -// unrecognized fields. To avoid this, DiscardUnknown is used to -// explicitly clear the unknown fields after unmarshaling. -// -// For proto2 messages, the unknown fields of message extensions are only -// discarded from messages that have been accessed via GetExtension. -func DiscardUnknown(m Message) { - discardLegacy(m) -} - -func discardLegacy(m Message) { - v := reflect.ValueOf(m) - if v.Kind() != reflect.Ptr || v.IsNil() { - return - } - v = v.Elem() - if v.Kind() != reflect.Struct { - return - } - t := v.Type() - - for i := 0; i < v.NumField(); i++ { - f := t.Field(i) - if strings.HasPrefix(f.Name, "XXX_") { - continue - } - vf := v.Field(i) - tf := f.Type - - // Unwrap tf to get its most basic type. - var isPointer, isSlice bool - if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 { - isSlice = true - tf = tf.Elem() - } - if tf.Kind() == reflect.Ptr { - isPointer = true - tf = tf.Elem() - } - if isPointer && isSlice && tf.Kind() != reflect.Struct { - panic(fmt.Sprintf("%T.%s cannot be a slice of pointers to primitive types", m, f.Name)) - } - - switch tf.Kind() { - case reflect.Struct: - switch { - case !isPointer: - panic(fmt.Sprintf("%T.%s cannot be a direct struct value", m, f.Name)) - case isSlice: // E.g., []*pb.T - for j := 0; j < vf.Len(); j++ { - discardLegacy(vf.Index(j).Interface().(Message)) - } - default: // E.g., *pb.T - discardLegacy(vf.Interface().(Message)) - } - case reflect.Map: - switch { - case isPointer || isSlice: - panic(fmt.Sprintf("%T.%s cannot be a pointer to a map or a slice of map values", m, f.Name)) - default: // E.g., map[K]V - tv := vf.Type().Elem() - if tv.Kind() == reflect.Ptr && tv.Implements(protoMessageType) { // Proto struct (e.g., *T) - for _, key := range vf.MapKeys() { - val := vf.MapIndex(key) - discardLegacy(val.Interface().(Message)) - } - } - } - case reflect.Interface: - // Must be oneof field. - switch { - case isPointer || isSlice: - panic(fmt.Sprintf("%T.%s cannot be a pointer to a interface or a slice of interface values", m, f.Name)) - default: // E.g., test_proto.isCommunique_Union interface - if !vf.IsNil() && f.Tag.Get("protobuf_oneof") != "" { - vf = vf.Elem() // E.g., *test_proto.Communique_Msg - if !vf.IsNil() { - vf = vf.Elem() // E.g., test_proto.Communique_Msg - vf = vf.Field(0) // E.g., Proto struct (e.g., *T) or primitive value - if vf.Kind() == reflect.Ptr { - discardLegacy(vf.Interface().(Message)) - } - } - } - } - } - } - - if vf := v.FieldByName("XXX_unrecognized"); vf.IsValid() { - if vf.Type() != reflect.TypeOf([]byte{}) { - panic("expected XXX_unrecognized to be of type []byte") - } - vf.Set(reflect.ValueOf([]byte(nil))) - } - - // For proto2 messages, only discard unknown fields in message extensions - // that have been accessed via GetExtension. - if em, ok := extendable(m); ok { - // Ignore lock since discardLegacy is not concurrency safe. - emm, _ := em.extensionsRead() - for _, mx := range emm { - if m, ok := mx.value.(Message); ok { - discardLegacy(m) - } - } - } -} diff --git a/vendor/github.com/golang/protobuf/proto/encode.go b/vendor/github.com/golang/protobuf/proto/encode.go deleted file mode 100644 index 8b84d1b..0000000 --- a/vendor/github.com/golang/protobuf/proto/encode.go +++ /dev/null @@ -1,1362 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -/* - * Routines for encoding data into the wire format for protocol buffers. - */ - -import ( - "errors" - "fmt" - "reflect" - "sort" -) - -// RequiredNotSetError is the error returned if Marshal is called with -// a protocol buffer struct whose required fields have not -// all been initialized. It is also the error returned if Unmarshal is -// called with an encoded protocol buffer that does not include all the -// required fields. -// -// When printed, RequiredNotSetError reports the first unset required field in a -// message. If the field cannot be precisely determined, it is reported as -// "{Unknown}". -type RequiredNotSetError struct { - field string -} - -func (e *RequiredNotSetError) Error() string { - return fmt.Sprintf("proto: required field %q not set", e.field) -} - -var ( - // errRepeatedHasNil is the error returned if Marshal is called with - // a struct with a repeated field containing a nil element. - errRepeatedHasNil = errors.New("proto: repeated field has nil element") - - // errOneofHasNil is the error returned if Marshal is called with - // a struct with a oneof field containing a nil element. - errOneofHasNil = errors.New("proto: oneof field has nil value") - - // ErrNil is the error returned if Marshal is called with nil. - ErrNil = errors.New("proto: Marshal called with nil") - - // ErrTooLarge is the error returned if Marshal is called with a - // message that encodes to >2GB. - ErrTooLarge = errors.New("proto: message encodes to over 2 GB") -) - -// The fundamental encoders that put bytes on the wire. -// Those that take integer types all accept uint64 and are -// therefore of type valueEncoder. - -const maxVarintBytes = 10 // maximum length of a varint - -// maxMarshalSize is the largest allowed size of an encoded protobuf, -// since C++ and Java use signed int32s for the size. -const maxMarshalSize = 1<<31 - 1 - -// EncodeVarint returns the varint encoding of x. -// This is the format for the -// int32, int64, uint32, uint64, bool, and enum -// protocol buffer types. -// Not used by the package itself, but helpful to clients -// wishing to use the same encoding. -func EncodeVarint(x uint64) []byte { - var buf [maxVarintBytes]byte - var n int - for n = 0; x > 127; n++ { - buf[n] = 0x80 | uint8(x&0x7F) - x >>= 7 - } - buf[n] = uint8(x) - n++ - return buf[0:n] -} - -// EncodeVarint writes a varint-encoded integer to the Buffer. -// This is the format for the -// int32, int64, uint32, uint64, bool, and enum -// protocol buffer types. -func (p *Buffer) EncodeVarint(x uint64) error { - for x >= 1<<7 { - p.buf = append(p.buf, uint8(x&0x7f|0x80)) - x >>= 7 - } - p.buf = append(p.buf, uint8(x)) - return nil -} - -// SizeVarint returns the varint encoding size of an integer. -func SizeVarint(x uint64) int { - return sizeVarint(x) -} - -func sizeVarint(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n -} - -// EncodeFixed64 writes a 64-bit integer to the Buffer. -// This is the format for the -// fixed64, sfixed64, and double protocol buffer types. -func (p *Buffer) EncodeFixed64(x uint64) error { - p.buf = append(p.buf, - uint8(x), - uint8(x>>8), - uint8(x>>16), - uint8(x>>24), - uint8(x>>32), - uint8(x>>40), - uint8(x>>48), - uint8(x>>56)) - return nil -} - -func sizeFixed64(x uint64) int { - return 8 -} - -// EncodeFixed32 writes a 32-bit integer to the Buffer. -// This is the format for the -// fixed32, sfixed32, and float protocol buffer types. -func (p *Buffer) EncodeFixed32(x uint64) error { - p.buf = append(p.buf, - uint8(x), - uint8(x>>8), - uint8(x>>16), - uint8(x>>24)) - return nil -} - -func sizeFixed32(x uint64) int { - return 4 -} - -// EncodeZigzag64 writes a zigzag-encoded 64-bit integer -// to the Buffer. -// This is the format used for the sint64 protocol buffer type. -func (p *Buffer) EncodeZigzag64(x uint64) error { - // use signed number to get arithmetic right shift. - return p.EncodeVarint((x << 1) ^ uint64((int64(x) >> 63))) -} - -func sizeZigzag64(x uint64) int { - return sizeVarint((x << 1) ^ uint64((int64(x) >> 63))) -} - -// EncodeZigzag32 writes a zigzag-encoded 32-bit integer -// to the Buffer. -// This is the format used for the sint32 protocol buffer type. -func (p *Buffer) EncodeZigzag32(x uint64) error { - // use signed number to get arithmetic right shift. - return p.EncodeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31)))) -} - -func sizeZigzag32(x uint64) int { - return sizeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31)))) -} - -// EncodeRawBytes writes a count-delimited byte buffer to the Buffer. -// This is the format used for the bytes protocol buffer -// type and for embedded messages. -func (p *Buffer) EncodeRawBytes(b []byte) error { - p.EncodeVarint(uint64(len(b))) - p.buf = append(p.buf, b...) - return nil -} - -func sizeRawBytes(b []byte) int { - return sizeVarint(uint64(len(b))) + - len(b) -} - -// EncodeStringBytes writes an encoded string to the Buffer. -// This is the format used for the proto2 string type. -func (p *Buffer) EncodeStringBytes(s string) error { - p.EncodeVarint(uint64(len(s))) - p.buf = append(p.buf, s...) - return nil -} - -func sizeStringBytes(s string) int { - return sizeVarint(uint64(len(s))) + - len(s) -} - -// Marshaler is the interface representing objects that can marshal themselves. -type Marshaler interface { - Marshal() ([]byte, error) -} - -// Marshal takes the protocol buffer -// and encodes it into the wire format, returning the data. -func Marshal(pb Message) ([]byte, error) { - // Can the object marshal itself? - if m, ok := pb.(Marshaler); ok { - return m.Marshal() - } - p := NewBuffer(nil) - err := p.Marshal(pb) - if p.buf == nil && err == nil { - // Return a non-nil slice on success. - return []byte{}, nil - } - return p.buf, err -} - -// EncodeMessage writes the protocol buffer to the Buffer, -// prefixed by a varint-encoded length. -func (p *Buffer) EncodeMessage(pb Message) error { - t, base, err := getbase(pb) - if structPointer_IsNil(base) { - return ErrNil - } - if err == nil { - var state errorState - err = p.enc_len_struct(GetProperties(t.Elem()), base, &state) - } - return err -} - -// Marshal takes the protocol buffer -// and encodes it into the wire format, writing the result to the -// Buffer. -func (p *Buffer) Marshal(pb Message) error { - // Can the object marshal itself? - if m, ok := pb.(Marshaler); ok { - data, err := m.Marshal() - p.buf = append(p.buf, data...) - return err - } - - t, base, err := getbase(pb) - if structPointer_IsNil(base) { - return ErrNil - } - if err == nil { - err = p.enc_struct(GetProperties(t.Elem()), base) - } - - if collectStats { - (stats).Encode++ // Parens are to work around a goimports bug. - } - - if len(p.buf) > maxMarshalSize { - return ErrTooLarge - } - return err -} - -// Size returns the encoded size of a protocol buffer. -func Size(pb Message) (n int) { - // Can the object marshal itself? If so, Size is slow. - // TODO: add Size to Marshaler, or add a Sizer interface. - if m, ok := pb.(Marshaler); ok { - b, _ := m.Marshal() - return len(b) - } - - t, base, err := getbase(pb) - if structPointer_IsNil(base) { - return 0 - } - if err == nil { - n = size_struct(GetProperties(t.Elem()), base) - } - - if collectStats { - (stats).Size++ // Parens are to work around a goimports bug. - } - - return -} - -// Individual type encoders. - -// Encode a bool. -func (o *Buffer) enc_bool(p *Properties, base structPointer) error { - v := *structPointer_Bool(base, p.field) - if v == nil { - return ErrNil - } - x := 0 - if *v { - x = 1 - } - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, uint64(x)) - return nil -} - -func (o *Buffer) enc_proto3_bool(p *Properties, base structPointer) error { - v := *structPointer_BoolVal(base, p.field) - if !v { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, 1) - return nil -} - -func size_bool(p *Properties, base structPointer) int { - v := *structPointer_Bool(base, p.field) - if v == nil { - return 0 - } - return len(p.tagcode) + 1 // each bool takes exactly one byte -} - -func size_proto3_bool(p *Properties, base structPointer) int { - v := *structPointer_BoolVal(base, p.field) - if !v && !p.oneof { - return 0 - } - return len(p.tagcode) + 1 // each bool takes exactly one byte -} - -// Encode an int32. -func (o *Buffer) enc_int32(p *Properties, base structPointer) error { - v := structPointer_Word32(base, p.field) - if word32_IsNil(v) { - return ErrNil - } - x := int32(word32_Get(v)) // permit sign extension to use full 64-bit range - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, uint64(x)) - return nil -} - -func (o *Buffer) enc_proto3_int32(p *Properties, base structPointer) error { - v := structPointer_Word32Val(base, p.field) - x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range - if x == 0 { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, uint64(x)) - return nil -} - -func size_int32(p *Properties, base structPointer) (n int) { - v := structPointer_Word32(base, p.field) - if word32_IsNil(v) { - return 0 - } - x := int32(word32_Get(v)) // permit sign extension to use full 64-bit range - n += len(p.tagcode) - n += p.valSize(uint64(x)) - return -} - -func size_proto3_int32(p *Properties, base structPointer) (n int) { - v := structPointer_Word32Val(base, p.field) - x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range - if x == 0 && !p.oneof { - return 0 - } - n += len(p.tagcode) - n += p.valSize(uint64(x)) - return -} - -// Encode a uint32. -// Exactly the same as int32, except for no sign extension. -func (o *Buffer) enc_uint32(p *Properties, base structPointer) error { - v := structPointer_Word32(base, p.field) - if word32_IsNil(v) { - return ErrNil - } - x := word32_Get(v) - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, uint64(x)) - return nil -} - -func (o *Buffer) enc_proto3_uint32(p *Properties, base structPointer) error { - v := structPointer_Word32Val(base, p.field) - x := word32Val_Get(v) - if x == 0 { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, uint64(x)) - return nil -} - -func size_uint32(p *Properties, base structPointer) (n int) { - v := structPointer_Word32(base, p.field) - if word32_IsNil(v) { - return 0 - } - x := word32_Get(v) - n += len(p.tagcode) - n += p.valSize(uint64(x)) - return -} - -func size_proto3_uint32(p *Properties, base structPointer) (n int) { - v := structPointer_Word32Val(base, p.field) - x := word32Val_Get(v) - if x == 0 && !p.oneof { - return 0 - } - n += len(p.tagcode) - n += p.valSize(uint64(x)) - return -} - -// Encode an int64. -func (o *Buffer) enc_int64(p *Properties, base structPointer) error { - v := structPointer_Word64(base, p.field) - if word64_IsNil(v) { - return ErrNil - } - x := word64_Get(v) - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, x) - return nil -} - -func (o *Buffer) enc_proto3_int64(p *Properties, base structPointer) error { - v := structPointer_Word64Val(base, p.field) - x := word64Val_Get(v) - if x == 0 { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, x) - return nil -} - -func size_int64(p *Properties, base structPointer) (n int) { - v := structPointer_Word64(base, p.field) - if word64_IsNil(v) { - return 0 - } - x := word64_Get(v) - n += len(p.tagcode) - n += p.valSize(x) - return -} - -func size_proto3_int64(p *Properties, base structPointer) (n int) { - v := structPointer_Word64Val(base, p.field) - x := word64Val_Get(v) - if x == 0 && !p.oneof { - return 0 - } - n += len(p.tagcode) - n += p.valSize(x) - return -} - -// Encode a string. -func (o *Buffer) enc_string(p *Properties, base structPointer) error { - v := *structPointer_String(base, p.field) - if v == nil { - return ErrNil - } - x := *v - o.buf = append(o.buf, p.tagcode...) - o.EncodeStringBytes(x) - return nil -} - -func (o *Buffer) enc_proto3_string(p *Properties, base structPointer) error { - v := *structPointer_StringVal(base, p.field) - if v == "" { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - o.EncodeStringBytes(v) - return nil -} - -func size_string(p *Properties, base structPointer) (n int) { - v := *structPointer_String(base, p.field) - if v == nil { - return 0 - } - x := *v - n += len(p.tagcode) - n += sizeStringBytes(x) - return -} - -func size_proto3_string(p *Properties, base structPointer) (n int) { - v := *structPointer_StringVal(base, p.field) - if v == "" && !p.oneof { - return 0 - } - n += len(p.tagcode) - n += sizeStringBytes(v) - return -} - -// All protocol buffer fields are nillable, but be careful. -func isNil(v reflect.Value) bool { - switch v.Kind() { - case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: - return v.IsNil() - } - return false -} - -// Encode a message struct. -func (o *Buffer) enc_struct_message(p *Properties, base structPointer) error { - var state errorState - structp := structPointer_GetStructPointer(base, p.field) - if structPointer_IsNil(structp) { - return ErrNil - } - - // Can the object marshal itself? - if p.isMarshaler { - m := structPointer_Interface(structp, p.stype).(Marshaler) - data, err := m.Marshal() - if err != nil && !state.shouldContinue(err, nil) { - return err - } - o.buf = append(o.buf, p.tagcode...) - o.EncodeRawBytes(data) - return state.err - } - - o.buf = append(o.buf, p.tagcode...) - return o.enc_len_struct(p.sprop, structp, &state) -} - -func size_struct_message(p *Properties, base structPointer) int { - structp := structPointer_GetStructPointer(base, p.field) - if structPointer_IsNil(structp) { - return 0 - } - - // Can the object marshal itself? - if p.isMarshaler { - m := structPointer_Interface(structp, p.stype).(Marshaler) - data, _ := m.Marshal() - n0 := len(p.tagcode) - n1 := sizeRawBytes(data) - return n0 + n1 - } - - n0 := len(p.tagcode) - n1 := size_struct(p.sprop, structp) - n2 := sizeVarint(uint64(n1)) // size of encoded length - return n0 + n1 + n2 -} - -// Encode a group struct. -func (o *Buffer) enc_struct_group(p *Properties, base structPointer) error { - var state errorState - b := structPointer_GetStructPointer(base, p.field) - if structPointer_IsNil(b) { - return ErrNil - } - - o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup)) - err := o.enc_struct(p.sprop, b) - if err != nil && !state.shouldContinue(err, nil) { - return err - } - o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup)) - return state.err -} - -func size_struct_group(p *Properties, base structPointer) (n int) { - b := structPointer_GetStructPointer(base, p.field) - if structPointer_IsNil(b) { - return 0 - } - - n += sizeVarint(uint64((p.Tag << 3) | WireStartGroup)) - n += size_struct(p.sprop, b) - n += sizeVarint(uint64((p.Tag << 3) | WireEndGroup)) - return -} - -// Encode a slice of bools ([]bool). -func (o *Buffer) enc_slice_bool(p *Properties, base structPointer) error { - s := *structPointer_BoolSlice(base, p.field) - l := len(s) - if l == 0 { - return ErrNil - } - for _, x := range s { - o.buf = append(o.buf, p.tagcode...) - v := uint64(0) - if x { - v = 1 - } - p.valEnc(o, v) - } - return nil -} - -func size_slice_bool(p *Properties, base structPointer) int { - s := *structPointer_BoolSlice(base, p.field) - l := len(s) - if l == 0 { - return 0 - } - return l * (len(p.tagcode) + 1) // each bool takes exactly one byte -} - -// Encode a slice of bools ([]bool) in packed format. -func (o *Buffer) enc_slice_packed_bool(p *Properties, base structPointer) error { - s := *structPointer_BoolSlice(base, p.field) - l := len(s) - if l == 0 { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - o.EncodeVarint(uint64(l)) // each bool takes exactly one byte - for _, x := range s { - v := uint64(0) - if x { - v = 1 - } - p.valEnc(o, v) - } - return nil -} - -func size_slice_packed_bool(p *Properties, base structPointer) (n int) { - s := *structPointer_BoolSlice(base, p.field) - l := len(s) - if l == 0 { - return 0 - } - n += len(p.tagcode) - n += sizeVarint(uint64(l)) - n += l // each bool takes exactly one byte - return -} - -// Encode a slice of bytes ([]byte). -func (o *Buffer) enc_slice_byte(p *Properties, base structPointer) error { - s := *structPointer_Bytes(base, p.field) - if s == nil { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - o.EncodeRawBytes(s) - return nil -} - -func (o *Buffer) enc_proto3_slice_byte(p *Properties, base structPointer) error { - s := *structPointer_Bytes(base, p.field) - if len(s) == 0 { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - o.EncodeRawBytes(s) - return nil -} - -func size_slice_byte(p *Properties, base structPointer) (n int) { - s := *structPointer_Bytes(base, p.field) - if s == nil && !p.oneof { - return 0 - } - n += len(p.tagcode) - n += sizeRawBytes(s) - return -} - -func size_proto3_slice_byte(p *Properties, base structPointer) (n int) { - s := *structPointer_Bytes(base, p.field) - if len(s) == 0 && !p.oneof { - return 0 - } - n += len(p.tagcode) - n += sizeRawBytes(s) - return -} - -// Encode a slice of int32s ([]int32). -func (o *Buffer) enc_slice_int32(p *Properties, base structPointer) error { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return ErrNil - } - for i := 0; i < l; i++ { - o.buf = append(o.buf, p.tagcode...) - x := int32(s.Index(i)) // permit sign extension to use full 64-bit range - p.valEnc(o, uint64(x)) - } - return nil -} - -func size_slice_int32(p *Properties, base structPointer) (n int) { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return 0 - } - for i := 0; i < l; i++ { - n += len(p.tagcode) - x := int32(s.Index(i)) // permit sign extension to use full 64-bit range - n += p.valSize(uint64(x)) - } - return -} - -// Encode a slice of int32s ([]int32) in packed format. -func (o *Buffer) enc_slice_packed_int32(p *Properties, base structPointer) error { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return ErrNil - } - // TODO: Reuse a Buffer. - buf := NewBuffer(nil) - for i := 0; i < l; i++ { - x := int32(s.Index(i)) // permit sign extension to use full 64-bit range - p.valEnc(buf, uint64(x)) - } - - o.buf = append(o.buf, p.tagcode...) - o.EncodeVarint(uint64(len(buf.buf))) - o.buf = append(o.buf, buf.buf...) - return nil -} - -func size_slice_packed_int32(p *Properties, base structPointer) (n int) { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return 0 - } - var bufSize int - for i := 0; i < l; i++ { - x := int32(s.Index(i)) // permit sign extension to use full 64-bit range - bufSize += p.valSize(uint64(x)) - } - - n += len(p.tagcode) - n += sizeVarint(uint64(bufSize)) - n += bufSize - return -} - -// Encode a slice of uint32s ([]uint32). -// Exactly the same as int32, except for no sign extension. -func (o *Buffer) enc_slice_uint32(p *Properties, base structPointer) error { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return ErrNil - } - for i := 0; i < l; i++ { - o.buf = append(o.buf, p.tagcode...) - x := s.Index(i) - p.valEnc(o, uint64(x)) - } - return nil -} - -func size_slice_uint32(p *Properties, base structPointer) (n int) { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return 0 - } - for i := 0; i < l; i++ { - n += len(p.tagcode) - x := s.Index(i) - n += p.valSize(uint64(x)) - } - return -} - -// Encode a slice of uint32s ([]uint32) in packed format. -// Exactly the same as int32, except for no sign extension. -func (o *Buffer) enc_slice_packed_uint32(p *Properties, base structPointer) error { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return ErrNil - } - // TODO: Reuse a Buffer. - buf := NewBuffer(nil) - for i := 0; i < l; i++ { - p.valEnc(buf, uint64(s.Index(i))) - } - - o.buf = append(o.buf, p.tagcode...) - o.EncodeVarint(uint64(len(buf.buf))) - o.buf = append(o.buf, buf.buf...) - return nil -} - -func size_slice_packed_uint32(p *Properties, base structPointer) (n int) { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return 0 - } - var bufSize int - for i := 0; i < l; i++ { - bufSize += p.valSize(uint64(s.Index(i))) - } - - n += len(p.tagcode) - n += sizeVarint(uint64(bufSize)) - n += bufSize - return -} - -// Encode a slice of int64s ([]int64). -func (o *Buffer) enc_slice_int64(p *Properties, base structPointer) error { - s := structPointer_Word64Slice(base, p.field) - l := s.Len() - if l == 0 { - return ErrNil - } - for i := 0; i < l; i++ { - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, s.Index(i)) - } - return nil -} - -func size_slice_int64(p *Properties, base structPointer) (n int) { - s := structPointer_Word64Slice(base, p.field) - l := s.Len() - if l == 0 { - return 0 - } - for i := 0; i < l; i++ { - n += len(p.tagcode) - n += p.valSize(s.Index(i)) - } - return -} - -// Encode a slice of int64s ([]int64) in packed format. -func (o *Buffer) enc_slice_packed_int64(p *Properties, base structPointer) error { - s := structPointer_Word64Slice(base, p.field) - l := s.Len() - if l == 0 { - return ErrNil - } - // TODO: Reuse a Buffer. - buf := NewBuffer(nil) - for i := 0; i < l; i++ { - p.valEnc(buf, s.Index(i)) - } - - o.buf = append(o.buf, p.tagcode...) - o.EncodeVarint(uint64(len(buf.buf))) - o.buf = append(o.buf, buf.buf...) - return nil -} - -func size_slice_packed_int64(p *Properties, base structPointer) (n int) { - s := structPointer_Word64Slice(base, p.field) - l := s.Len() - if l == 0 { - return 0 - } - var bufSize int - for i := 0; i < l; i++ { - bufSize += p.valSize(s.Index(i)) - } - - n += len(p.tagcode) - n += sizeVarint(uint64(bufSize)) - n += bufSize - return -} - -// Encode a slice of slice of bytes ([][]byte). -func (o *Buffer) enc_slice_slice_byte(p *Properties, base structPointer) error { - ss := *structPointer_BytesSlice(base, p.field) - l := len(ss) - if l == 0 { - return ErrNil - } - for i := 0; i < l; i++ { - o.buf = append(o.buf, p.tagcode...) - o.EncodeRawBytes(ss[i]) - } - return nil -} - -func size_slice_slice_byte(p *Properties, base structPointer) (n int) { - ss := *structPointer_BytesSlice(base, p.field) - l := len(ss) - if l == 0 { - return 0 - } - n += l * len(p.tagcode) - for i := 0; i < l; i++ { - n += sizeRawBytes(ss[i]) - } - return -} - -// Encode a slice of strings ([]string). -func (o *Buffer) enc_slice_string(p *Properties, base structPointer) error { - ss := *structPointer_StringSlice(base, p.field) - l := len(ss) - for i := 0; i < l; i++ { - o.buf = append(o.buf, p.tagcode...) - o.EncodeStringBytes(ss[i]) - } - return nil -} - -func size_slice_string(p *Properties, base structPointer) (n int) { - ss := *structPointer_StringSlice(base, p.field) - l := len(ss) - n += l * len(p.tagcode) - for i := 0; i < l; i++ { - n += sizeStringBytes(ss[i]) - } - return -} - -// Encode a slice of message structs ([]*struct). -func (o *Buffer) enc_slice_struct_message(p *Properties, base structPointer) error { - var state errorState - s := structPointer_StructPointerSlice(base, p.field) - l := s.Len() - - for i := 0; i < l; i++ { - structp := s.Index(i) - if structPointer_IsNil(structp) { - return errRepeatedHasNil - } - - // Can the object marshal itself? - if p.isMarshaler { - m := structPointer_Interface(structp, p.stype).(Marshaler) - data, err := m.Marshal() - if err != nil && !state.shouldContinue(err, nil) { - return err - } - o.buf = append(o.buf, p.tagcode...) - o.EncodeRawBytes(data) - continue - } - - o.buf = append(o.buf, p.tagcode...) - err := o.enc_len_struct(p.sprop, structp, &state) - if err != nil && !state.shouldContinue(err, nil) { - if err == ErrNil { - return errRepeatedHasNil - } - return err - } - } - return state.err -} - -func size_slice_struct_message(p *Properties, base structPointer) (n int) { - s := structPointer_StructPointerSlice(base, p.field) - l := s.Len() - n += l * len(p.tagcode) - for i := 0; i < l; i++ { - structp := s.Index(i) - if structPointer_IsNil(structp) { - return // return the size up to this point - } - - // Can the object marshal itself? - if p.isMarshaler { - m := structPointer_Interface(structp, p.stype).(Marshaler) - data, _ := m.Marshal() - n += sizeRawBytes(data) - continue - } - - n0 := size_struct(p.sprop, structp) - n1 := sizeVarint(uint64(n0)) // size of encoded length - n += n0 + n1 - } - return -} - -// Encode a slice of group structs ([]*struct). -func (o *Buffer) enc_slice_struct_group(p *Properties, base structPointer) error { - var state errorState - s := structPointer_StructPointerSlice(base, p.field) - l := s.Len() - - for i := 0; i < l; i++ { - b := s.Index(i) - if structPointer_IsNil(b) { - return errRepeatedHasNil - } - - o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup)) - - err := o.enc_struct(p.sprop, b) - - if err != nil && !state.shouldContinue(err, nil) { - if err == ErrNil { - return errRepeatedHasNil - } - return err - } - - o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup)) - } - return state.err -} - -func size_slice_struct_group(p *Properties, base structPointer) (n int) { - s := structPointer_StructPointerSlice(base, p.field) - l := s.Len() - - n += l * sizeVarint(uint64((p.Tag<<3)|WireStartGroup)) - n += l * sizeVarint(uint64((p.Tag<<3)|WireEndGroup)) - for i := 0; i < l; i++ { - b := s.Index(i) - if structPointer_IsNil(b) { - return // return size up to this point - } - - n += size_struct(p.sprop, b) - } - return -} - -// Encode an extension map. -func (o *Buffer) enc_map(p *Properties, base structPointer) error { - exts := structPointer_ExtMap(base, p.field) - if err := encodeExtensionsMap(*exts); err != nil { - return err - } - - return o.enc_map_body(*exts) -} - -func (o *Buffer) enc_exts(p *Properties, base structPointer) error { - exts := structPointer_Extensions(base, p.field) - - v, mu := exts.extensionsRead() - if v == nil { - return nil - } - - mu.Lock() - defer mu.Unlock() - if err := encodeExtensionsMap(v); err != nil { - return err - } - - return o.enc_map_body(v) -} - -func (o *Buffer) enc_map_body(v map[int32]Extension) error { - // Fast-path for common cases: zero or one extensions. - if len(v) <= 1 { - for _, e := range v { - o.buf = append(o.buf, e.enc...) - } - return nil - } - - // Sort keys to provide a deterministic encoding. - keys := make([]int, 0, len(v)) - for k := range v { - keys = append(keys, int(k)) - } - sort.Ints(keys) - - for _, k := range keys { - o.buf = append(o.buf, v[int32(k)].enc...) - } - return nil -} - -func size_map(p *Properties, base structPointer) int { - v := structPointer_ExtMap(base, p.field) - return extensionsMapSize(*v) -} - -func size_exts(p *Properties, base structPointer) int { - v := structPointer_Extensions(base, p.field) - return extensionsSize(v) -} - -// Encode a map field. -func (o *Buffer) enc_new_map(p *Properties, base structPointer) error { - var state errorState // XXX: or do we need to plumb this through? - - /* - A map defined as - map map_field = N; - is encoded in the same way as - message MapFieldEntry { - key_type key = 1; - value_type value = 2; - } - repeated MapFieldEntry map_field = N; - */ - - v := structPointer_NewAt(base, p.field, p.mtype).Elem() // map[K]V - if v.Len() == 0 { - return nil - } - - keycopy, valcopy, keybase, valbase := mapEncodeScratch(p.mtype) - - enc := func() error { - if err := p.mkeyprop.enc(o, p.mkeyprop, keybase); err != nil { - return err - } - if err := p.mvalprop.enc(o, p.mvalprop, valbase); err != nil && err != ErrNil { - return err - } - return nil - } - - // Don't sort map keys. It is not required by the spec, and C++ doesn't do it. - for _, key := range v.MapKeys() { - val := v.MapIndex(key) - - keycopy.Set(key) - valcopy.Set(val) - - o.buf = append(o.buf, p.tagcode...) - if err := o.enc_len_thing(enc, &state); err != nil { - return err - } - } - return nil -} - -func size_new_map(p *Properties, base structPointer) int { - v := structPointer_NewAt(base, p.field, p.mtype).Elem() // map[K]V - - keycopy, valcopy, keybase, valbase := mapEncodeScratch(p.mtype) - - n := 0 - for _, key := range v.MapKeys() { - val := v.MapIndex(key) - keycopy.Set(key) - valcopy.Set(val) - - // Tag codes for key and val are the responsibility of the sub-sizer. - keysize := p.mkeyprop.size(p.mkeyprop, keybase) - valsize := p.mvalprop.size(p.mvalprop, valbase) - entry := keysize + valsize - // Add on tag code and length of map entry itself. - n += len(p.tagcode) + sizeVarint(uint64(entry)) + entry - } - return n -} - -// mapEncodeScratch returns a new reflect.Value matching the map's value type, -// and a structPointer suitable for passing to an encoder or sizer. -func mapEncodeScratch(mapType reflect.Type) (keycopy, valcopy reflect.Value, keybase, valbase structPointer) { - // Prepare addressable doubly-indirect placeholders for the key and value types. - // This is needed because the element-type encoders expect **T, but the map iteration produces T. - - keycopy = reflect.New(mapType.Key()).Elem() // addressable K - keyptr := reflect.New(reflect.PtrTo(keycopy.Type())).Elem() // addressable *K - keyptr.Set(keycopy.Addr()) // - keybase = toStructPointer(keyptr.Addr()) // **K - - // Value types are more varied and require special handling. - switch mapType.Elem().Kind() { - case reflect.Slice: - // []byte - var dummy []byte - valcopy = reflect.ValueOf(&dummy).Elem() // addressable []byte - valbase = toStructPointer(valcopy.Addr()) - case reflect.Ptr: - // message; the generated field type is map[K]*Msg (so V is *Msg), - // so we only need one level of indirection. - valcopy = reflect.New(mapType.Elem()).Elem() // addressable V - valbase = toStructPointer(valcopy.Addr()) - default: - // everything else - valcopy = reflect.New(mapType.Elem()).Elem() // addressable V - valptr := reflect.New(reflect.PtrTo(valcopy.Type())).Elem() // addressable *V - valptr.Set(valcopy.Addr()) // - valbase = toStructPointer(valptr.Addr()) // **V - } - return -} - -// Encode a struct. -func (o *Buffer) enc_struct(prop *StructProperties, base structPointer) error { - var state errorState - // Encode fields in tag order so that decoders may use optimizations - // that depend on the ordering. - // https://developers.google.com/protocol-buffers/docs/encoding#order - for _, i := range prop.order { - p := prop.Prop[i] - if p.enc != nil { - err := p.enc(o, p, base) - if err != nil { - if err == ErrNil { - if p.Required && state.err == nil { - state.err = &RequiredNotSetError{p.Name} - } - } else if err == errRepeatedHasNil { - // Give more context to nil values in repeated fields. - return errors.New("repeated field " + p.OrigName + " has nil element") - } else if !state.shouldContinue(err, p) { - return err - } - } - if len(o.buf) > maxMarshalSize { - return ErrTooLarge - } - } - } - - // Do oneof fields. - if prop.oneofMarshaler != nil { - m := structPointer_Interface(base, prop.stype).(Message) - if err := prop.oneofMarshaler(m, o); err == ErrNil { - return errOneofHasNil - } else if err != nil { - return err - } - } - - // Add unrecognized fields at the end. - if prop.unrecField.IsValid() { - v := *structPointer_Bytes(base, prop.unrecField) - if len(o.buf)+len(v) > maxMarshalSize { - return ErrTooLarge - } - if len(v) > 0 { - o.buf = append(o.buf, v...) - } - } - - return state.err -} - -func size_struct(prop *StructProperties, base structPointer) (n int) { - for _, i := range prop.order { - p := prop.Prop[i] - if p.size != nil { - n += p.size(p, base) - } - } - - // Add unrecognized fields at the end. - if prop.unrecField.IsValid() { - v := *structPointer_Bytes(base, prop.unrecField) - n += len(v) - } - - // Factor in any oneof fields. - if prop.oneofSizer != nil { - m := structPointer_Interface(base, prop.stype).(Message) - n += prop.oneofSizer(m) - } - - return -} - -var zeroes [20]byte // longer than any conceivable sizeVarint - -// Encode a struct, preceded by its encoded length (as a varint). -func (o *Buffer) enc_len_struct(prop *StructProperties, base structPointer, state *errorState) error { - return o.enc_len_thing(func() error { return o.enc_struct(prop, base) }, state) -} - -// Encode something, preceded by its encoded length (as a varint). -func (o *Buffer) enc_len_thing(enc func() error, state *errorState) error { - iLen := len(o.buf) - o.buf = append(o.buf, 0, 0, 0, 0) // reserve four bytes for length - iMsg := len(o.buf) - err := enc() - if err != nil && !state.shouldContinue(err, nil) { - return err - } - lMsg := len(o.buf) - iMsg - lLen := sizeVarint(uint64(lMsg)) - switch x := lLen - (iMsg - iLen); { - case x > 0: // actual length is x bytes larger than the space we reserved - // Move msg x bytes right. - o.buf = append(o.buf, zeroes[:x]...) - copy(o.buf[iMsg+x:], o.buf[iMsg:iMsg+lMsg]) - case x < 0: // actual length is x bytes smaller than the space we reserved - // Move msg x bytes left. - copy(o.buf[iMsg+x:], o.buf[iMsg:iMsg+lMsg]) - o.buf = o.buf[:len(o.buf)+x] // x is negative - } - // Encode the length in the reserved space. - o.buf = o.buf[:iLen] - o.EncodeVarint(uint64(lMsg)) - o.buf = o.buf[:len(o.buf)+lMsg] - return state.err -} - -// errorState maintains the first error that occurs and updates that error -// with additional context. -type errorState struct { - err error -} - -// shouldContinue reports whether encoding should continue upon encountering the -// given error. If the error is RequiredNotSetError, shouldContinue returns true -// and, if this is the first appearance of that error, remembers it for future -// reporting. -// -// If prop is not nil, it may update any error with additional context about the -// field with the error. -func (s *errorState) shouldContinue(err error, prop *Properties) bool { - // Ignore unset required fields. - reqNotSet, ok := err.(*RequiredNotSetError) - if !ok { - return false - } - if s.err == nil { - if prop != nil { - err = &RequiredNotSetError{prop.Name + "." + reqNotSet.field} - } - s.err = err - } - return true -} diff --git a/vendor/github.com/golang/protobuf/proto/equal.go b/vendor/github.com/golang/protobuf/proto/equal.go deleted file mode 100644 index 2ed1cf5..0000000 --- a/vendor/github.com/golang/protobuf/proto/equal.go +++ /dev/null @@ -1,300 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2011 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Protocol buffer comparison. - -package proto - -import ( - "bytes" - "log" - "reflect" - "strings" -) - -/* -Equal returns true iff protocol buffers a and b are equal. -The arguments must both be pointers to protocol buffer structs. - -Equality is defined in this way: - - Two messages are equal iff they are the same type, - corresponding fields are equal, unknown field sets - are equal, and extensions sets are equal. - - Two set scalar fields are equal iff their values are equal. - If the fields are of a floating-point type, remember that - NaN != x for all x, including NaN. If the message is defined - in a proto3 .proto file, fields are not "set"; specifically, - zero length proto3 "bytes" fields are equal (nil == {}). - - Two repeated fields are equal iff their lengths are the same, - and their corresponding elements are equal. Note a "bytes" field, - although represented by []byte, is not a repeated field and the - rule for the scalar fields described above applies. - - Two unset fields are equal. - - Two unknown field sets are equal if their current - encoded state is equal. - - Two extension sets are equal iff they have corresponding - elements that are pairwise equal. - - Two map fields are equal iff their lengths are the same, - and they contain the same set of elements. Zero-length map - fields are equal. - - Every other combination of things are not equal. - -The return value is undefined if a and b are not protocol buffers. -*/ -func Equal(a, b Message) bool { - if a == nil || b == nil { - return a == b - } - v1, v2 := reflect.ValueOf(a), reflect.ValueOf(b) - if v1.Type() != v2.Type() { - return false - } - if v1.Kind() == reflect.Ptr { - if v1.IsNil() { - return v2.IsNil() - } - if v2.IsNil() { - return false - } - v1, v2 = v1.Elem(), v2.Elem() - } - if v1.Kind() != reflect.Struct { - return false - } - return equalStruct(v1, v2) -} - -// v1 and v2 are known to have the same type. -func equalStruct(v1, v2 reflect.Value) bool { - sprop := GetProperties(v1.Type()) - for i := 0; i < v1.NumField(); i++ { - f := v1.Type().Field(i) - if strings.HasPrefix(f.Name, "XXX_") { - continue - } - f1, f2 := v1.Field(i), v2.Field(i) - if f.Type.Kind() == reflect.Ptr { - if n1, n2 := f1.IsNil(), f2.IsNil(); n1 && n2 { - // both unset - continue - } else if n1 != n2 { - // set/unset mismatch - return false - } - b1, ok := f1.Interface().(raw) - if ok { - b2 := f2.Interface().(raw) - // RawMessage - if !bytes.Equal(b1.Bytes(), b2.Bytes()) { - return false - } - continue - } - f1, f2 = f1.Elem(), f2.Elem() - } - if !equalAny(f1, f2, sprop.Prop[i]) { - return false - } - } - - if em1 := v1.FieldByName("XXX_InternalExtensions"); em1.IsValid() { - em2 := v2.FieldByName("XXX_InternalExtensions") - if !equalExtensions(v1.Type(), em1.Interface().(XXX_InternalExtensions), em2.Interface().(XXX_InternalExtensions)) { - return false - } - } - - if em1 := v1.FieldByName("XXX_extensions"); em1.IsValid() { - em2 := v2.FieldByName("XXX_extensions") - if !equalExtMap(v1.Type(), em1.Interface().(map[int32]Extension), em2.Interface().(map[int32]Extension)) { - return false - } - } - - uf := v1.FieldByName("XXX_unrecognized") - if !uf.IsValid() { - return true - } - - u1 := uf.Bytes() - u2 := v2.FieldByName("XXX_unrecognized").Bytes() - if !bytes.Equal(u1, u2) { - return false - } - - return true -} - -// v1 and v2 are known to have the same type. -// prop may be nil. -func equalAny(v1, v2 reflect.Value, prop *Properties) bool { - if v1.Type() == protoMessageType { - m1, _ := v1.Interface().(Message) - m2, _ := v2.Interface().(Message) - return Equal(m1, m2) - } - switch v1.Kind() { - case reflect.Bool: - return v1.Bool() == v2.Bool() - case reflect.Float32, reflect.Float64: - return v1.Float() == v2.Float() - case reflect.Int32, reflect.Int64: - return v1.Int() == v2.Int() - case reflect.Interface: - // Probably a oneof field; compare the inner values. - n1, n2 := v1.IsNil(), v2.IsNil() - if n1 || n2 { - return n1 == n2 - } - e1, e2 := v1.Elem(), v2.Elem() - if e1.Type() != e2.Type() { - return false - } - return equalAny(e1, e2, nil) - case reflect.Map: - if v1.Len() != v2.Len() { - return false - } - for _, key := range v1.MapKeys() { - val2 := v2.MapIndex(key) - if !val2.IsValid() { - // This key was not found in the second map. - return false - } - if !equalAny(v1.MapIndex(key), val2, nil) { - return false - } - } - return true - case reflect.Ptr: - // Maps may have nil values in them, so check for nil. - if v1.IsNil() && v2.IsNil() { - return true - } - if v1.IsNil() != v2.IsNil() { - return false - } - return equalAny(v1.Elem(), v2.Elem(), prop) - case reflect.Slice: - if v1.Type().Elem().Kind() == reflect.Uint8 { - // short circuit: []byte - - // Edge case: if this is in a proto3 message, a zero length - // bytes field is considered the zero value. - if prop != nil && prop.proto3 && v1.Len() == 0 && v2.Len() == 0 { - return true - } - if v1.IsNil() != v2.IsNil() { - return false - } - return bytes.Equal(v1.Interface().([]byte), v2.Interface().([]byte)) - } - - if v1.Len() != v2.Len() { - return false - } - for i := 0; i < v1.Len(); i++ { - if !equalAny(v1.Index(i), v2.Index(i), prop) { - return false - } - } - return true - case reflect.String: - return v1.Interface().(string) == v2.Interface().(string) - case reflect.Struct: - return equalStruct(v1, v2) - case reflect.Uint32, reflect.Uint64: - return v1.Uint() == v2.Uint() - } - - // unknown type, so not a protocol buffer - log.Printf("proto: don't know how to compare %v", v1) - return false -} - -// base is the struct type that the extensions are based on. -// x1 and x2 are InternalExtensions. -func equalExtensions(base reflect.Type, x1, x2 XXX_InternalExtensions) bool { - em1, _ := x1.extensionsRead() - em2, _ := x2.extensionsRead() - return equalExtMap(base, em1, em2) -} - -func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool { - if len(em1) != len(em2) { - return false - } - - for extNum, e1 := range em1 { - e2, ok := em2[extNum] - if !ok { - return false - } - - m1, m2 := e1.value, e2.value - - if m1 != nil && m2 != nil { - // Both are unencoded. - if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) { - return false - } - continue - } - - // At least one is encoded. To do a semantically correct comparison - // we need to unmarshal them first. - var desc *ExtensionDesc - if m := extensionMaps[base]; m != nil { - desc = m[extNum] - } - if desc == nil { - log.Printf("proto: don't know how to compare extension %d of %v", extNum, base) - continue - } - var err error - if m1 == nil { - m1, err = decodeExtension(e1.enc, desc) - } - if m2 == nil && err == nil { - m2, err = decodeExtension(e2.enc, desc) - } - if err != nil { - // The encoded form is invalid. - log.Printf("proto: badly encoded extension %d of %v: %v", extNum, base, err) - return false - } - if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) { - return false - } - } - - return true -} diff --git a/vendor/github.com/golang/protobuf/proto/extensions.go b/vendor/github.com/golang/protobuf/proto/extensions.go deleted file mode 100644 index eaad218..0000000 --- a/vendor/github.com/golang/protobuf/proto/extensions.go +++ /dev/null @@ -1,587 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -/* - * Types and routines for supporting protocol buffer extensions. - */ - -import ( - "errors" - "fmt" - "reflect" - "strconv" - "sync" -) - -// ErrMissingExtension is the error returned by GetExtension if the named extension is not in the message. -var ErrMissingExtension = errors.New("proto: missing extension") - -// ExtensionRange represents a range of message extensions for a protocol buffer. -// Used in code generated by the protocol compiler. -type ExtensionRange struct { - Start, End int32 // both inclusive -} - -// extendableProto is an interface implemented by any protocol buffer generated by the current -// proto compiler that may be extended. -type extendableProto interface { - Message - ExtensionRangeArray() []ExtensionRange - extensionsWrite() map[int32]Extension - extensionsRead() (map[int32]Extension, sync.Locker) -} - -// extendableProtoV1 is an interface implemented by a protocol buffer generated by the previous -// version of the proto compiler that may be extended. -type extendableProtoV1 interface { - Message - ExtensionRangeArray() []ExtensionRange - ExtensionMap() map[int32]Extension -} - -// extensionAdapter is a wrapper around extendableProtoV1 that implements extendableProto. -type extensionAdapter struct { - extendableProtoV1 -} - -func (e extensionAdapter) extensionsWrite() map[int32]Extension { - return e.ExtensionMap() -} - -func (e extensionAdapter) extensionsRead() (map[int32]Extension, sync.Locker) { - return e.ExtensionMap(), notLocker{} -} - -// notLocker is a sync.Locker whose Lock and Unlock methods are nops. -type notLocker struct{} - -func (n notLocker) Lock() {} -func (n notLocker) Unlock() {} - -// extendable returns the extendableProto interface for the given generated proto message. -// If the proto message has the old extension format, it returns a wrapper that implements -// the extendableProto interface. -func extendable(p interface{}) (extendableProto, bool) { - if ep, ok := p.(extendableProto); ok { - return ep, ok - } - if ep, ok := p.(extendableProtoV1); ok { - return extensionAdapter{ep}, ok - } - return nil, false -} - -// XXX_InternalExtensions is an internal representation of proto extensions. -// -// Each generated message struct type embeds an anonymous XXX_InternalExtensions field, -// thus gaining the unexported 'extensions' method, which can be called only from the proto package. -// -// The methods of XXX_InternalExtensions are not concurrency safe in general, -// but calls to logically read-only methods such as has and get may be executed concurrently. -type XXX_InternalExtensions struct { - // The struct must be indirect so that if a user inadvertently copies a - // generated message and its embedded XXX_InternalExtensions, they - // avoid the mayhem of a copied mutex. - // - // The mutex serializes all logically read-only operations to p.extensionMap. - // It is up to the client to ensure that write operations to p.extensionMap are - // mutually exclusive with other accesses. - p *struct { - mu sync.Mutex - extensionMap map[int32]Extension - } -} - -// extensionsWrite returns the extension map, creating it on first use. -func (e *XXX_InternalExtensions) extensionsWrite() map[int32]Extension { - if e.p == nil { - e.p = new(struct { - mu sync.Mutex - extensionMap map[int32]Extension - }) - e.p.extensionMap = make(map[int32]Extension) - } - return e.p.extensionMap -} - -// extensionsRead returns the extensions map for read-only use. It may be nil. -// The caller must hold the returned mutex's lock when accessing Elements within the map. -func (e *XXX_InternalExtensions) extensionsRead() (map[int32]Extension, sync.Locker) { - if e.p == nil { - return nil, nil - } - return e.p.extensionMap, &e.p.mu -} - -var extendableProtoType = reflect.TypeOf((*extendableProto)(nil)).Elem() -var extendableProtoV1Type = reflect.TypeOf((*extendableProtoV1)(nil)).Elem() - -// ExtensionDesc represents an extension specification. -// Used in generated code from the protocol compiler. -type ExtensionDesc struct { - ExtendedType Message // nil pointer to the type that is being extended - ExtensionType interface{} // nil pointer to the extension type - Field int32 // field number - Name string // fully-qualified name of extension, for text formatting - Tag string // protobuf tag style - Filename string // name of the file in which the extension is defined -} - -func (ed *ExtensionDesc) repeated() bool { - t := reflect.TypeOf(ed.ExtensionType) - return t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 -} - -// Extension represents an extension in a message. -type Extension struct { - // When an extension is stored in a message using SetExtension - // only desc and value are set. When the message is marshaled - // enc will be set to the encoded form of the message. - // - // When a message is unmarshaled and contains extensions, each - // extension will have only enc set. When such an extension is - // accessed using GetExtension (or GetExtensions) desc and value - // will be set. - desc *ExtensionDesc - value interface{} - enc []byte -} - -// SetRawExtension is for testing only. -func SetRawExtension(base Message, id int32, b []byte) { - epb, ok := extendable(base) - if !ok { - return - } - extmap := epb.extensionsWrite() - extmap[id] = Extension{enc: b} -} - -// isExtensionField returns true iff the given field number is in an extension range. -func isExtensionField(pb extendableProto, field int32) bool { - for _, er := range pb.ExtensionRangeArray() { - if er.Start <= field && field <= er.End { - return true - } - } - return false -} - -// checkExtensionTypes checks that the given extension is valid for pb. -func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error { - var pbi interface{} = pb - // Check the extended type. - if ea, ok := pbi.(extensionAdapter); ok { - pbi = ea.extendableProtoV1 - } - if a, b := reflect.TypeOf(pbi), reflect.TypeOf(extension.ExtendedType); a != b { - return errors.New("proto: bad extended type; " + b.String() + " does not extend " + a.String()) - } - // Check the range. - if !isExtensionField(pb, extension.Field) { - return errors.New("proto: bad extension number; not in declared ranges") - } - return nil -} - -// extPropKey is sufficient to uniquely identify an extension. -type extPropKey struct { - base reflect.Type - field int32 -} - -var extProp = struct { - sync.RWMutex - m map[extPropKey]*Properties -}{ - m: make(map[extPropKey]*Properties), -} - -func extensionProperties(ed *ExtensionDesc) *Properties { - key := extPropKey{base: reflect.TypeOf(ed.ExtendedType), field: ed.Field} - - extProp.RLock() - if prop, ok := extProp.m[key]; ok { - extProp.RUnlock() - return prop - } - extProp.RUnlock() - - extProp.Lock() - defer extProp.Unlock() - // Check again. - if prop, ok := extProp.m[key]; ok { - return prop - } - - prop := new(Properties) - prop.Init(reflect.TypeOf(ed.ExtensionType), "unknown_name", ed.Tag, nil) - extProp.m[key] = prop - return prop -} - -// encode encodes any unmarshaled (unencoded) extensions in e. -func encodeExtensions(e *XXX_InternalExtensions) error { - m, mu := e.extensionsRead() - if m == nil { - return nil // fast path - } - mu.Lock() - defer mu.Unlock() - return encodeExtensionsMap(m) -} - -// encode encodes any unmarshaled (unencoded) extensions in e. -func encodeExtensionsMap(m map[int32]Extension) error { - for k, e := range m { - if e.value == nil || e.desc == nil { - // Extension is only in its encoded form. - continue - } - - // We don't skip extensions that have an encoded form set, - // because the extension value may have been mutated after - // the last time this function was called. - - et := reflect.TypeOf(e.desc.ExtensionType) - props := extensionProperties(e.desc) - - p := NewBuffer(nil) - // If e.value has type T, the encoder expects a *struct{ X T }. - // Pass a *T with a zero field and hope it all works out. - x := reflect.New(et) - x.Elem().Set(reflect.ValueOf(e.value)) - if err := props.enc(p, props, toStructPointer(x)); err != nil { - return err - } - e.enc = p.buf - m[k] = e - } - return nil -} - -func extensionsSize(e *XXX_InternalExtensions) (n int) { - m, mu := e.extensionsRead() - if m == nil { - return 0 - } - mu.Lock() - defer mu.Unlock() - return extensionsMapSize(m) -} - -func extensionsMapSize(m map[int32]Extension) (n int) { - for _, e := range m { - if e.value == nil || e.desc == nil { - // Extension is only in its encoded form. - n += len(e.enc) - continue - } - - // We don't skip extensions that have an encoded form set, - // because the extension value may have been mutated after - // the last time this function was called. - - et := reflect.TypeOf(e.desc.ExtensionType) - props := extensionProperties(e.desc) - - // If e.value has type T, the encoder expects a *struct{ X T }. - // Pass a *T with a zero field and hope it all works out. - x := reflect.New(et) - x.Elem().Set(reflect.ValueOf(e.value)) - n += props.size(props, toStructPointer(x)) - } - return -} - -// HasExtension returns whether the given extension is present in pb. -func HasExtension(pb Message, extension *ExtensionDesc) bool { - // TODO: Check types, field numbers, etc.? - epb, ok := extendable(pb) - if !ok { - return false - } - extmap, mu := epb.extensionsRead() - if extmap == nil { - return false - } - mu.Lock() - _, ok = extmap[extension.Field] - mu.Unlock() - return ok -} - -// ClearExtension removes the given extension from pb. -func ClearExtension(pb Message, extension *ExtensionDesc) { - epb, ok := extendable(pb) - if !ok { - return - } - // TODO: Check types, field numbers, etc.? - extmap := epb.extensionsWrite() - delete(extmap, extension.Field) -} - -// GetExtension parses and returns the given extension of pb. -// If the extension is not present and has no default value it returns ErrMissingExtension. -func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) { - epb, ok := extendable(pb) - if !ok { - return nil, errors.New("proto: not an extendable proto") - } - - if err := checkExtensionTypes(epb, extension); err != nil { - return nil, err - } - - emap, mu := epb.extensionsRead() - if emap == nil { - return defaultExtensionValue(extension) - } - mu.Lock() - defer mu.Unlock() - e, ok := emap[extension.Field] - if !ok { - // defaultExtensionValue returns the default value or - // ErrMissingExtension if there is no default. - return defaultExtensionValue(extension) - } - - if e.value != nil { - // Already decoded. Check the descriptor, though. - if e.desc != extension { - // This shouldn't happen. If it does, it means that - // GetExtension was called twice with two different - // descriptors with the same field number. - return nil, errors.New("proto: descriptor conflict") - } - return e.value, nil - } - - v, err := decodeExtension(e.enc, extension) - if err != nil { - return nil, err - } - - // Remember the decoded version and drop the encoded version. - // That way it is safe to mutate what we return. - e.value = v - e.desc = extension - e.enc = nil - emap[extension.Field] = e - return e.value, nil -} - -// defaultExtensionValue returns the default value for extension. -// If no default for an extension is defined ErrMissingExtension is returned. -func defaultExtensionValue(extension *ExtensionDesc) (interface{}, error) { - t := reflect.TypeOf(extension.ExtensionType) - props := extensionProperties(extension) - - sf, _, err := fieldDefault(t, props) - if err != nil { - return nil, err - } - - if sf == nil || sf.value == nil { - // There is no default value. - return nil, ErrMissingExtension - } - - if t.Kind() != reflect.Ptr { - // We do not need to return a Ptr, we can directly return sf.value. - return sf.value, nil - } - - // We need to return an interface{} that is a pointer to sf.value. - value := reflect.New(t).Elem() - value.Set(reflect.New(value.Type().Elem())) - if sf.kind == reflect.Int32 { - // We may have an int32 or an enum, but the underlying data is int32. - // Since we can't set an int32 into a non int32 reflect.value directly - // set it as a int32. - value.Elem().SetInt(int64(sf.value.(int32))) - } else { - value.Elem().Set(reflect.ValueOf(sf.value)) - } - return value.Interface(), nil -} - -// decodeExtension decodes an extension encoded in b. -func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) { - o := NewBuffer(b) - - t := reflect.TypeOf(extension.ExtensionType) - - props := extensionProperties(extension) - - // t is a pointer to a struct, pointer to basic type or a slice. - // Allocate a "field" to store the pointer/slice itself; the - // pointer/slice will be stored here. We pass - // the address of this field to props.dec. - // This passes a zero field and a *t and lets props.dec - // interpret it as a *struct{ x t }. - value := reflect.New(t).Elem() - - for { - // Discard wire type and field number varint. It isn't needed. - if _, err := o.DecodeVarint(); err != nil { - return nil, err - } - - if err := props.dec(o, props, toStructPointer(value.Addr())); err != nil { - return nil, err - } - - if o.index >= len(o.buf) { - break - } - } - return value.Interface(), nil -} - -// GetExtensions returns a slice of the extensions present in pb that are also listed in es. -// The returned slice has the same length as es; missing extensions will appear as nil elements. -func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) { - epb, ok := extendable(pb) - if !ok { - return nil, errors.New("proto: not an extendable proto") - } - extensions = make([]interface{}, len(es)) - for i, e := range es { - extensions[i], err = GetExtension(epb, e) - if err == ErrMissingExtension { - err = nil - } - if err != nil { - return - } - } - return -} - -// ExtensionDescs returns a new slice containing pb's extension descriptors, in undefined order. -// For non-registered extensions, ExtensionDescs returns an incomplete descriptor containing -// just the Field field, which defines the extension's field number. -func ExtensionDescs(pb Message) ([]*ExtensionDesc, error) { - epb, ok := extendable(pb) - if !ok { - return nil, fmt.Errorf("proto: %T is not an extendable proto.Message", pb) - } - registeredExtensions := RegisteredExtensions(pb) - - emap, mu := epb.extensionsRead() - if emap == nil { - return nil, nil - } - mu.Lock() - defer mu.Unlock() - extensions := make([]*ExtensionDesc, 0, len(emap)) - for extid, e := range emap { - desc := e.desc - if desc == nil { - desc = registeredExtensions[extid] - if desc == nil { - desc = &ExtensionDesc{Field: extid} - } - } - - extensions = append(extensions, desc) - } - return extensions, nil -} - -// SetExtension sets the specified extension of pb to the specified value. -func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error { - epb, ok := extendable(pb) - if !ok { - return errors.New("proto: not an extendable proto") - } - if err := checkExtensionTypes(epb, extension); err != nil { - return err - } - typ := reflect.TypeOf(extension.ExtensionType) - if typ != reflect.TypeOf(value) { - return errors.New("proto: bad extension value type") - } - // nil extension values need to be caught early, because the - // encoder can't distinguish an ErrNil due to a nil extension - // from an ErrNil due to a missing field. Extensions are - // always optional, so the encoder would just swallow the error - // and drop all the extensions from the encoded message. - if reflect.ValueOf(value).IsNil() { - return fmt.Errorf("proto: SetExtension called with nil value of type %T", value) - } - - extmap := epb.extensionsWrite() - extmap[extension.Field] = Extension{desc: extension, value: value} - return nil -} - -// ClearAllExtensions clears all extensions from pb. -func ClearAllExtensions(pb Message) { - epb, ok := extendable(pb) - if !ok { - return - } - m := epb.extensionsWrite() - for k := range m { - delete(m, k) - } -} - -// A global registry of extensions. -// The generated code will register the generated descriptors by calling RegisterExtension. - -var extensionMaps = make(map[reflect.Type]map[int32]*ExtensionDesc) - -// RegisterExtension is called from the generated code. -func RegisterExtension(desc *ExtensionDesc) { - st := reflect.TypeOf(desc.ExtendedType).Elem() - m := extensionMaps[st] - if m == nil { - m = make(map[int32]*ExtensionDesc) - extensionMaps[st] = m - } - if _, ok := m[desc.Field]; ok { - panic("proto: duplicate extension registered: " + st.String() + " " + strconv.Itoa(int(desc.Field))) - } - m[desc.Field] = desc -} - -// RegisteredExtensions returns a map of the registered extensions of a -// protocol buffer struct, indexed by the extension number. -// The argument pb should be a nil pointer to the struct type. -func RegisteredExtensions(pb Message) map[int32]*ExtensionDesc { - return extensionMaps[reflect.TypeOf(pb).Elem()] -} diff --git a/vendor/github.com/golang/protobuf/proto/lib.go b/vendor/github.com/golang/protobuf/proto/lib.go deleted file mode 100644 index 1c22550..0000000 --- a/vendor/github.com/golang/protobuf/proto/lib.go +++ /dev/null @@ -1,897 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -/* -Package proto converts data structures to and from the wire format of -protocol buffers. It works in concert with the Go source code generated -for .proto files by the protocol compiler. - -A summary of the properties of the protocol buffer interface -for a protocol buffer variable v: - - - Names are turned from camel_case to CamelCase for export. - - There are no methods on v to set fields; just treat - them as structure fields. - - There are getters that return a field's value if set, - and return the field's default value if unset. - The getters work even if the receiver is a nil message. - - The zero value for a struct is its correct initialization state. - All desired fields must be set before marshaling. - - A Reset() method will restore a protobuf struct to its zero state. - - Non-repeated fields are pointers to the values; nil means unset. - That is, optional or required field int32 f becomes F *int32. - - Repeated fields are slices. - - Helper functions are available to aid the setting of fields. - msg.Foo = proto.String("hello") // set field - - Constants are defined to hold the default values of all fields that - have them. They have the form Default_StructName_FieldName. - Because the getter methods handle defaulted values, - direct use of these constants should be rare. - - Enums are given type names and maps from names to values. - Enum values are prefixed by the enclosing message's name, or by the - enum's type name if it is a top-level enum. Enum types have a String - method, and a Enum method to assist in message construction. - - Nested messages, groups and enums have type names prefixed with the name of - the surrounding message type. - - Extensions are given descriptor names that start with E_, - followed by an underscore-delimited list of the nested messages - that contain it (if any) followed by the CamelCased name of the - extension field itself. HasExtension, ClearExtension, GetExtension - and SetExtension are functions for manipulating extensions. - - Oneof field sets are given a single field in their message, - with distinguished wrapper types for each possible field value. - - Marshal and Unmarshal are functions to encode and decode the wire format. - -When the .proto file specifies `syntax="proto3"`, there are some differences: - - - Non-repeated fields of non-message type are values instead of pointers. - - Enum types do not get an Enum method. - -The simplest way to describe this is to see an example. -Given file test.proto, containing - - package example; - - enum FOO { X = 17; } - - message Test { - required string label = 1; - optional int32 type = 2 [default=77]; - repeated int64 reps = 3; - optional group OptionalGroup = 4 { - required string RequiredField = 5; - } - oneof union { - int32 number = 6; - string name = 7; - } - } - -The resulting file, test.pb.go, is: - - package example - - import proto "github.com/golang/protobuf/proto" - import math "math" - - type FOO int32 - const ( - FOO_X FOO = 17 - ) - var FOO_name = map[int32]string{ - 17: "X", - } - var FOO_value = map[string]int32{ - "X": 17, - } - - func (x FOO) Enum() *FOO { - p := new(FOO) - *p = x - return p - } - func (x FOO) String() string { - return proto.EnumName(FOO_name, int32(x)) - } - func (x *FOO) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(FOO_value, data) - if err != nil { - return err - } - *x = FOO(value) - return nil - } - - type Test struct { - Label *string `protobuf:"bytes,1,req,name=label" json:"label,omitempty"` - Type *int32 `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"` - Reps []int64 `protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"` - Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"` - // Types that are valid to be assigned to Union: - // *Test_Number - // *Test_Name - Union isTest_Union `protobuf_oneof:"union"` - XXX_unrecognized []byte `json:"-"` - } - func (m *Test) Reset() { *m = Test{} } - func (m *Test) String() string { return proto.CompactTextString(m) } - func (*Test) ProtoMessage() {} - - type isTest_Union interface { - isTest_Union() - } - - type Test_Number struct { - Number int32 `protobuf:"varint,6,opt,name=number"` - } - type Test_Name struct { - Name string `protobuf:"bytes,7,opt,name=name"` - } - - func (*Test_Number) isTest_Union() {} - func (*Test_Name) isTest_Union() {} - - func (m *Test) GetUnion() isTest_Union { - if m != nil { - return m.Union - } - return nil - } - const Default_Test_Type int32 = 77 - - func (m *Test) GetLabel() string { - if m != nil && m.Label != nil { - return *m.Label - } - return "" - } - - func (m *Test) GetType() int32 { - if m != nil && m.Type != nil { - return *m.Type - } - return Default_Test_Type - } - - func (m *Test) GetOptionalgroup() *Test_OptionalGroup { - if m != nil { - return m.Optionalgroup - } - return nil - } - - type Test_OptionalGroup struct { - RequiredField *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"` - } - func (m *Test_OptionalGroup) Reset() { *m = Test_OptionalGroup{} } - func (m *Test_OptionalGroup) String() string { return proto.CompactTextString(m) } - - func (m *Test_OptionalGroup) GetRequiredField() string { - if m != nil && m.RequiredField != nil { - return *m.RequiredField - } - return "" - } - - func (m *Test) GetNumber() int32 { - if x, ok := m.GetUnion().(*Test_Number); ok { - return x.Number - } - return 0 - } - - func (m *Test) GetName() string { - if x, ok := m.GetUnion().(*Test_Name); ok { - return x.Name - } - return "" - } - - func init() { - proto.RegisterEnum("example.FOO", FOO_name, FOO_value) - } - -To create and play with a Test object: - - package main - - import ( - "log" - - "github.com/golang/protobuf/proto" - pb "./example.pb" - ) - - func main() { - test := &pb.Test{ - Label: proto.String("hello"), - Type: proto.Int32(17), - Reps: []int64{1, 2, 3}, - Optionalgroup: &pb.Test_OptionalGroup{ - RequiredField: proto.String("good bye"), - }, - Union: &pb.Test_Name{"fred"}, - } - data, err := proto.Marshal(test) - if err != nil { - log.Fatal("marshaling error: ", err) - } - newTest := &pb.Test{} - err = proto.Unmarshal(data, newTest) - if err != nil { - log.Fatal("unmarshaling error: ", err) - } - // Now test and newTest contain the same data. - if test.GetLabel() != newTest.GetLabel() { - log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel()) - } - // Use a type switch to determine which oneof was set. - switch u := test.Union.(type) { - case *pb.Test_Number: // u.Number contains the number. - case *pb.Test_Name: // u.Name contains the string. - } - // etc. - } -*/ -package proto - -import ( - "encoding/json" - "fmt" - "log" - "reflect" - "sort" - "strconv" - "sync" -) - -// Message is implemented by generated protocol buffer messages. -type Message interface { - Reset() - String() string - ProtoMessage() -} - -// Stats records allocation details about the protocol buffer encoders -// and decoders. Useful for tuning the library itself. -type Stats struct { - Emalloc uint64 // mallocs in encode - Dmalloc uint64 // mallocs in decode - Encode uint64 // number of encodes - Decode uint64 // number of decodes - Chit uint64 // number of cache hits - Cmiss uint64 // number of cache misses - Size uint64 // number of sizes -} - -// Set to true to enable stats collection. -const collectStats = false - -var stats Stats - -// GetStats returns a copy of the global Stats structure. -func GetStats() Stats { return stats } - -// A Buffer is a buffer manager for marshaling and unmarshaling -// protocol buffers. It may be reused between invocations to -// reduce memory usage. It is not necessary to use a Buffer; -// the global functions Marshal and Unmarshal create a -// temporary Buffer and are fine for most applications. -type Buffer struct { - buf []byte // encode/decode byte stream - index int // read point - - // pools of basic types to amortize allocation. - bools []bool - uint32s []uint32 - uint64s []uint64 - - // extra pools, only used with pointer_reflect.go - int32s []int32 - int64s []int64 - float32s []float32 - float64s []float64 -} - -// NewBuffer allocates a new Buffer and initializes its internal data to -// the contents of the argument slice. -func NewBuffer(e []byte) *Buffer { - return &Buffer{buf: e} -} - -// Reset resets the Buffer, ready for marshaling a new protocol buffer. -func (p *Buffer) Reset() { - p.buf = p.buf[0:0] // for reading/writing - p.index = 0 // for reading -} - -// SetBuf replaces the internal buffer with the slice, -// ready for unmarshaling the contents of the slice. -func (p *Buffer) SetBuf(s []byte) { - p.buf = s - p.index = 0 -} - -// Bytes returns the contents of the Buffer. -func (p *Buffer) Bytes() []byte { return p.buf } - -/* - * Helper routines for simplifying the creation of optional fields of basic type. - */ - -// Bool is a helper routine that allocates a new bool value -// to store v and returns a pointer to it. -func Bool(v bool) *bool { - return &v -} - -// Int32 is a helper routine that allocates a new int32 value -// to store v and returns a pointer to it. -func Int32(v int32) *int32 { - return &v -} - -// Int is a helper routine that allocates a new int32 value -// to store v and returns a pointer to it, but unlike Int32 -// its argument value is an int. -func Int(v int) *int32 { - p := new(int32) - *p = int32(v) - return p -} - -// Int64 is a helper routine that allocates a new int64 value -// to store v and returns a pointer to it. -func Int64(v int64) *int64 { - return &v -} - -// Float32 is a helper routine that allocates a new float32 value -// to store v and returns a pointer to it. -func Float32(v float32) *float32 { - return &v -} - -// Float64 is a helper routine that allocates a new float64 value -// to store v and returns a pointer to it. -func Float64(v float64) *float64 { - return &v -} - -// Uint32 is a helper routine that allocates a new uint32 value -// to store v and returns a pointer to it. -func Uint32(v uint32) *uint32 { - return &v -} - -// Uint64 is a helper routine that allocates a new uint64 value -// to store v and returns a pointer to it. -func Uint64(v uint64) *uint64 { - return &v -} - -// String is a helper routine that allocates a new string value -// to store v and returns a pointer to it. -func String(v string) *string { - return &v -} - -// EnumName is a helper function to simplify printing protocol buffer enums -// by name. Given an enum map and a value, it returns a useful string. -func EnumName(m map[int32]string, v int32) string { - s, ok := m[v] - if ok { - return s - } - return strconv.Itoa(int(v)) -} - -// UnmarshalJSONEnum is a helper function to simplify recovering enum int values -// from their JSON-encoded representation. Given a map from the enum's symbolic -// names to its int values, and a byte buffer containing the JSON-encoded -// value, it returns an int32 that can be cast to the enum type by the caller. -// -// The function can deal with both JSON representations, numeric and symbolic. -func UnmarshalJSONEnum(m map[string]int32, data []byte, enumName string) (int32, error) { - if data[0] == '"' { - // New style: enums are strings. - var repr string - if err := json.Unmarshal(data, &repr); err != nil { - return -1, err - } - val, ok := m[repr] - if !ok { - return 0, fmt.Errorf("unrecognized enum %s value %q", enumName, repr) - } - return val, nil - } - // Old style: enums are ints. - var val int32 - if err := json.Unmarshal(data, &val); err != nil { - return 0, fmt.Errorf("cannot unmarshal %#q into enum %s", data, enumName) - } - return val, nil -} - -// DebugPrint dumps the encoded data in b in a debugging format with a header -// including the string s. Used in testing but made available for general debugging. -func (p *Buffer) DebugPrint(s string, b []byte) { - var u uint64 - - obuf := p.buf - index := p.index - p.buf = b - p.index = 0 - depth := 0 - - fmt.Printf("\n--- %s ---\n", s) - -out: - for { - for i := 0; i < depth; i++ { - fmt.Print(" ") - } - - index := p.index - if index == len(p.buf) { - break - } - - op, err := p.DecodeVarint() - if err != nil { - fmt.Printf("%3d: fetching op err %v\n", index, err) - break out - } - tag := op >> 3 - wire := op & 7 - - switch wire { - default: - fmt.Printf("%3d: t=%3d unknown wire=%d\n", - index, tag, wire) - break out - - case WireBytes: - var r []byte - - r, err = p.DecodeRawBytes(false) - if err != nil { - break out - } - fmt.Printf("%3d: t=%3d bytes [%d]", index, tag, len(r)) - if len(r) <= 6 { - for i := 0; i < len(r); i++ { - fmt.Printf(" %.2x", r[i]) - } - } else { - for i := 0; i < 3; i++ { - fmt.Printf(" %.2x", r[i]) - } - fmt.Printf(" ..") - for i := len(r) - 3; i < len(r); i++ { - fmt.Printf(" %.2x", r[i]) - } - } - fmt.Printf("\n") - - case WireFixed32: - u, err = p.DecodeFixed32() - if err != nil { - fmt.Printf("%3d: t=%3d fix32 err %v\n", index, tag, err) - break out - } - fmt.Printf("%3d: t=%3d fix32 %d\n", index, tag, u) - - case WireFixed64: - u, err = p.DecodeFixed64() - if err != nil { - fmt.Printf("%3d: t=%3d fix64 err %v\n", index, tag, err) - break out - } - fmt.Printf("%3d: t=%3d fix64 %d\n", index, tag, u) - - case WireVarint: - u, err = p.DecodeVarint() - if err != nil { - fmt.Printf("%3d: t=%3d varint err %v\n", index, tag, err) - break out - } - fmt.Printf("%3d: t=%3d varint %d\n", index, tag, u) - - case WireStartGroup: - fmt.Printf("%3d: t=%3d start\n", index, tag) - depth++ - - case WireEndGroup: - depth-- - fmt.Printf("%3d: t=%3d end\n", index, tag) - } - } - - if depth != 0 { - fmt.Printf("%3d: start-end not balanced %d\n", p.index, depth) - } - fmt.Printf("\n") - - p.buf = obuf - p.index = index -} - -// SetDefaults sets unset protocol buffer fields to their default values. -// It only modifies fields that are both unset and have defined defaults. -// It recursively sets default values in any non-nil sub-messages. -func SetDefaults(pb Message) { - setDefaults(reflect.ValueOf(pb), true, false) -} - -// v is a pointer to a struct. -func setDefaults(v reflect.Value, recur, zeros bool) { - v = v.Elem() - - defaultMu.RLock() - dm, ok := defaults[v.Type()] - defaultMu.RUnlock() - if !ok { - dm = buildDefaultMessage(v.Type()) - defaultMu.Lock() - defaults[v.Type()] = dm - defaultMu.Unlock() - } - - for _, sf := range dm.scalars { - f := v.Field(sf.index) - if !f.IsNil() { - // field already set - continue - } - dv := sf.value - if dv == nil && !zeros { - // no explicit default, and don't want to set zeros - continue - } - fptr := f.Addr().Interface() // **T - // TODO: Consider batching the allocations we do here. - switch sf.kind { - case reflect.Bool: - b := new(bool) - if dv != nil { - *b = dv.(bool) - } - *(fptr.(**bool)) = b - case reflect.Float32: - f := new(float32) - if dv != nil { - *f = dv.(float32) - } - *(fptr.(**float32)) = f - case reflect.Float64: - f := new(float64) - if dv != nil { - *f = dv.(float64) - } - *(fptr.(**float64)) = f - case reflect.Int32: - // might be an enum - if ft := f.Type(); ft != int32PtrType { - // enum - f.Set(reflect.New(ft.Elem())) - if dv != nil { - f.Elem().SetInt(int64(dv.(int32))) - } - } else { - // int32 field - i := new(int32) - if dv != nil { - *i = dv.(int32) - } - *(fptr.(**int32)) = i - } - case reflect.Int64: - i := new(int64) - if dv != nil { - *i = dv.(int64) - } - *(fptr.(**int64)) = i - case reflect.String: - s := new(string) - if dv != nil { - *s = dv.(string) - } - *(fptr.(**string)) = s - case reflect.Uint8: - // exceptional case: []byte - var b []byte - if dv != nil { - db := dv.([]byte) - b = make([]byte, len(db)) - copy(b, db) - } else { - b = []byte{} - } - *(fptr.(*[]byte)) = b - case reflect.Uint32: - u := new(uint32) - if dv != nil { - *u = dv.(uint32) - } - *(fptr.(**uint32)) = u - case reflect.Uint64: - u := new(uint64) - if dv != nil { - *u = dv.(uint64) - } - *(fptr.(**uint64)) = u - default: - log.Printf("proto: can't set default for field %v (sf.kind=%v)", f, sf.kind) - } - } - - for _, ni := range dm.nested { - f := v.Field(ni) - // f is *T or []*T or map[T]*T - switch f.Kind() { - case reflect.Ptr: - if f.IsNil() { - continue - } - setDefaults(f, recur, zeros) - - case reflect.Slice: - for i := 0; i < f.Len(); i++ { - e := f.Index(i) - if e.IsNil() { - continue - } - setDefaults(e, recur, zeros) - } - - case reflect.Map: - for _, k := range f.MapKeys() { - e := f.MapIndex(k) - if e.IsNil() { - continue - } - setDefaults(e, recur, zeros) - } - } - } -} - -var ( - // defaults maps a protocol buffer struct type to a slice of the fields, - // with its scalar fields set to their proto-declared non-zero default values. - defaultMu sync.RWMutex - defaults = make(map[reflect.Type]defaultMessage) - - int32PtrType = reflect.TypeOf((*int32)(nil)) -) - -// defaultMessage represents information about the default values of a message. -type defaultMessage struct { - scalars []scalarField - nested []int // struct field index of nested messages -} - -type scalarField struct { - index int // struct field index - kind reflect.Kind // element type (the T in *T or []T) - value interface{} // the proto-declared default value, or nil -} - -// t is a struct type. -func buildDefaultMessage(t reflect.Type) (dm defaultMessage) { - sprop := GetProperties(t) - for _, prop := range sprop.Prop { - fi, ok := sprop.decoderTags.get(prop.Tag) - if !ok { - // XXX_unrecognized - continue - } - ft := t.Field(fi).Type - - sf, nested, err := fieldDefault(ft, prop) - switch { - case err != nil: - log.Print(err) - case nested: - dm.nested = append(dm.nested, fi) - case sf != nil: - sf.index = fi - dm.scalars = append(dm.scalars, *sf) - } - } - - return dm -} - -// fieldDefault returns the scalarField for field type ft. -// sf will be nil if the field can not have a default. -// nestedMessage will be true if this is a nested message. -// Note that sf.index is not set on return. -func fieldDefault(ft reflect.Type, prop *Properties) (sf *scalarField, nestedMessage bool, err error) { - var canHaveDefault bool - switch ft.Kind() { - case reflect.Ptr: - if ft.Elem().Kind() == reflect.Struct { - nestedMessage = true - } else { - canHaveDefault = true // proto2 scalar field - } - - case reflect.Slice: - switch ft.Elem().Kind() { - case reflect.Ptr: - nestedMessage = true // repeated message - case reflect.Uint8: - canHaveDefault = true // bytes field - } - - case reflect.Map: - if ft.Elem().Kind() == reflect.Ptr { - nestedMessage = true // map with message values - } - } - - if !canHaveDefault { - if nestedMessage { - return nil, true, nil - } - return nil, false, nil - } - - // We now know that ft is a pointer or slice. - sf = &scalarField{kind: ft.Elem().Kind()} - - // scalar fields without defaults - if !prop.HasDefault { - return sf, false, nil - } - - // a scalar field: either *T or []byte - switch ft.Elem().Kind() { - case reflect.Bool: - x, err := strconv.ParseBool(prop.Default) - if err != nil { - return nil, false, fmt.Errorf("proto: bad default bool %q: %v", prop.Default, err) - } - sf.value = x - case reflect.Float32: - x, err := strconv.ParseFloat(prop.Default, 32) - if err != nil { - return nil, false, fmt.Errorf("proto: bad default float32 %q: %v", prop.Default, err) - } - sf.value = float32(x) - case reflect.Float64: - x, err := strconv.ParseFloat(prop.Default, 64) - if err != nil { - return nil, false, fmt.Errorf("proto: bad default float64 %q: %v", prop.Default, err) - } - sf.value = x - case reflect.Int32: - x, err := strconv.ParseInt(prop.Default, 10, 32) - if err != nil { - return nil, false, fmt.Errorf("proto: bad default int32 %q: %v", prop.Default, err) - } - sf.value = int32(x) - case reflect.Int64: - x, err := strconv.ParseInt(prop.Default, 10, 64) - if err != nil { - return nil, false, fmt.Errorf("proto: bad default int64 %q: %v", prop.Default, err) - } - sf.value = x - case reflect.String: - sf.value = prop.Default - case reflect.Uint8: - // []byte (not *uint8) - sf.value = []byte(prop.Default) - case reflect.Uint32: - x, err := strconv.ParseUint(prop.Default, 10, 32) - if err != nil { - return nil, false, fmt.Errorf("proto: bad default uint32 %q: %v", prop.Default, err) - } - sf.value = uint32(x) - case reflect.Uint64: - x, err := strconv.ParseUint(prop.Default, 10, 64) - if err != nil { - return nil, false, fmt.Errorf("proto: bad default uint64 %q: %v", prop.Default, err) - } - sf.value = x - default: - return nil, false, fmt.Errorf("proto: unhandled def kind %v", ft.Elem().Kind()) - } - - return sf, false, nil -} - -// Map fields may have key types of non-float scalars, strings and enums. -// The easiest way to sort them in some deterministic order is to use fmt. -// If this turns out to be inefficient we can always consider other options, -// such as doing a Schwartzian transform. - -func mapKeys(vs []reflect.Value) sort.Interface { - s := mapKeySorter{ - vs: vs, - // default Less function: textual comparison - less: func(a, b reflect.Value) bool { - return fmt.Sprint(a.Interface()) < fmt.Sprint(b.Interface()) - }, - } - - // Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps; - // numeric keys are sorted numerically. - if len(vs) == 0 { - return s - } - switch vs[0].Kind() { - case reflect.Int32, reflect.Int64: - s.less = func(a, b reflect.Value) bool { return a.Int() < b.Int() } - case reflect.Uint32, reflect.Uint64: - s.less = func(a, b reflect.Value) bool { return a.Uint() < b.Uint() } - } - - return s -} - -type mapKeySorter struct { - vs []reflect.Value - less func(a, b reflect.Value) bool -} - -func (s mapKeySorter) Len() int { return len(s.vs) } -func (s mapKeySorter) Swap(i, j int) { s.vs[i], s.vs[j] = s.vs[j], s.vs[i] } -func (s mapKeySorter) Less(i, j int) bool { - return s.less(s.vs[i], s.vs[j]) -} - -// isProto3Zero reports whether v is a zero proto3 value. -func isProto3Zero(v reflect.Value) bool { - switch v.Kind() { - case reflect.Bool: - return !v.Bool() - case reflect.Int32, reflect.Int64: - return v.Int() == 0 - case reflect.Uint32, reflect.Uint64: - return v.Uint() == 0 - case reflect.Float32, reflect.Float64: - return v.Float() == 0 - case reflect.String: - return v.String() == "" - } - return false -} - -// ProtoPackageIsVersion2 is referenced from generated protocol buffer files -// to assert that that code is compatible with this version of the proto package. -const ProtoPackageIsVersion2 = true - -// ProtoPackageIsVersion1 is referenced from generated protocol buffer files -// to assert that that code is compatible with this version of the proto package. -const ProtoPackageIsVersion1 = true diff --git a/vendor/github.com/golang/protobuf/proto/message_set.go b/vendor/github.com/golang/protobuf/proto/message_set.go deleted file mode 100644 index fd982de..0000000 --- a/vendor/github.com/golang/protobuf/proto/message_set.go +++ /dev/null @@ -1,311 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -/* - * Support for message sets. - */ - -import ( - "bytes" - "encoding/json" - "errors" - "fmt" - "reflect" - "sort" -) - -// errNoMessageTypeID occurs when a protocol buffer does not have a message type ID. -// A message type ID is required for storing a protocol buffer in a message set. -var errNoMessageTypeID = errors.New("proto does not have a message type ID") - -// The first two types (_MessageSet_Item and messageSet) -// model what the protocol compiler produces for the following protocol message: -// message MessageSet { -// repeated group Item = 1 { -// required int32 type_id = 2; -// required string message = 3; -// }; -// } -// That is the MessageSet wire format. We can't use a proto to generate these -// because that would introduce a circular dependency between it and this package. - -type _MessageSet_Item struct { - TypeId *int32 `protobuf:"varint,2,req,name=type_id"` - Message []byte `protobuf:"bytes,3,req,name=message"` -} - -type messageSet struct { - Item []*_MessageSet_Item `protobuf:"group,1,rep"` - XXX_unrecognized []byte - // TODO: caching? -} - -// Make sure messageSet is a Message. -var _ Message = (*messageSet)(nil) - -// messageTypeIder is an interface satisfied by a protocol buffer type -// that may be stored in a MessageSet. -type messageTypeIder interface { - MessageTypeId() int32 -} - -func (ms *messageSet) find(pb Message) *_MessageSet_Item { - mti, ok := pb.(messageTypeIder) - if !ok { - return nil - } - id := mti.MessageTypeId() - for _, item := range ms.Item { - if *item.TypeId == id { - return item - } - } - return nil -} - -func (ms *messageSet) Has(pb Message) bool { - if ms.find(pb) != nil { - return true - } - return false -} - -func (ms *messageSet) Unmarshal(pb Message) error { - if item := ms.find(pb); item != nil { - return Unmarshal(item.Message, pb) - } - if _, ok := pb.(messageTypeIder); !ok { - return errNoMessageTypeID - } - return nil // TODO: return error instead? -} - -func (ms *messageSet) Marshal(pb Message) error { - msg, err := Marshal(pb) - if err != nil { - return err - } - if item := ms.find(pb); item != nil { - // reuse existing item - item.Message = msg - return nil - } - - mti, ok := pb.(messageTypeIder) - if !ok { - return errNoMessageTypeID - } - - mtid := mti.MessageTypeId() - ms.Item = append(ms.Item, &_MessageSet_Item{ - TypeId: &mtid, - Message: msg, - }) - return nil -} - -func (ms *messageSet) Reset() { *ms = messageSet{} } -func (ms *messageSet) String() string { return CompactTextString(ms) } -func (*messageSet) ProtoMessage() {} - -// Support for the message_set_wire_format message option. - -func skipVarint(buf []byte) []byte { - i := 0 - for ; buf[i]&0x80 != 0; i++ { - } - return buf[i+1:] -} - -// MarshalMessageSet encodes the extension map represented by m in the message set wire format. -// It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option. -func MarshalMessageSet(exts interface{}) ([]byte, error) { - var m map[int32]Extension - switch exts := exts.(type) { - case *XXX_InternalExtensions: - if err := encodeExtensions(exts); err != nil { - return nil, err - } - m, _ = exts.extensionsRead() - case map[int32]Extension: - if err := encodeExtensionsMap(exts); err != nil { - return nil, err - } - m = exts - default: - return nil, errors.New("proto: not an extension map") - } - - // Sort extension IDs to provide a deterministic encoding. - // See also enc_map in encode.go. - ids := make([]int, 0, len(m)) - for id := range m { - ids = append(ids, int(id)) - } - sort.Ints(ids) - - ms := &messageSet{Item: make([]*_MessageSet_Item, 0, len(m))} - for _, id := range ids { - e := m[int32(id)] - // Remove the wire type and field number varint, as well as the length varint. - msg := skipVarint(skipVarint(e.enc)) - - ms.Item = append(ms.Item, &_MessageSet_Item{ - TypeId: Int32(int32(id)), - Message: msg, - }) - } - return Marshal(ms) -} - -// UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format. -// It is called by generated Unmarshal methods on protocol buffer messages with the message_set_wire_format option. -func UnmarshalMessageSet(buf []byte, exts interface{}) error { - var m map[int32]Extension - switch exts := exts.(type) { - case *XXX_InternalExtensions: - m = exts.extensionsWrite() - case map[int32]Extension: - m = exts - default: - return errors.New("proto: not an extension map") - } - - ms := new(messageSet) - if err := Unmarshal(buf, ms); err != nil { - return err - } - for _, item := range ms.Item { - id := *item.TypeId - msg := item.Message - - // Restore wire type and field number varint, plus length varint. - // Be careful to preserve duplicate items. - b := EncodeVarint(uint64(id)<<3 | WireBytes) - if ext, ok := m[id]; ok { - // Existing data; rip off the tag and length varint - // so we join the new data correctly. - // We can assume that ext.enc is set because we are unmarshaling. - o := ext.enc[len(b):] // skip wire type and field number - _, n := DecodeVarint(o) // calculate length of length varint - o = o[n:] // skip length varint - msg = append(o, msg...) // join old data and new data - } - b = append(b, EncodeVarint(uint64(len(msg)))...) - b = append(b, msg...) - - m[id] = Extension{enc: b} - } - return nil -} - -// MarshalMessageSetJSON encodes the extension map represented by m in JSON format. -// It is called by generated MarshalJSON methods on protocol buffer messages with the message_set_wire_format option. -func MarshalMessageSetJSON(exts interface{}) ([]byte, error) { - var m map[int32]Extension - switch exts := exts.(type) { - case *XXX_InternalExtensions: - m, _ = exts.extensionsRead() - case map[int32]Extension: - m = exts - default: - return nil, errors.New("proto: not an extension map") - } - var b bytes.Buffer - b.WriteByte('{') - - // Process the map in key order for deterministic output. - ids := make([]int32, 0, len(m)) - for id := range m { - ids = append(ids, id) - } - sort.Sort(int32Slice(ids)) // int32Slice defined in text.go - - for i, id := range ids { - ext := m[id] - if i > 0 { - b.WriteByte(',') - } - - msd, ok := messageSetMap[id] - if !ok { - // Unknown type; we can't render it, so skip it. - continue - } - fmt.Fprintf(&b, `"[%s]":`, msd.name) - - x := ext.value - if x == nil { - x = reflect.New(msd.t.Elem()).Interface() - if err := Unmarshal(ext.enc, x.(Message)); err != nil { - return nil, err - } - } - d, err := json.Marshal(x) - if err != nil { - return nil, err - } - b.Write(d) - } - b.WriteByte('}') - return b.Bytes(), nil -} - -// UnmarshalMessageSetJSON decodes the extension map encoded in buf in JSON format. -// It is called by generated UnmarshalJSON methods on protocol buffer messages with the message_set_wire_format option. -func UnmarshalMessageSetJSON(buf []byte, exts interface{}) error { - // Common-case fast path. - if len(buf) == 0 || bytes.Equal(buf, []byte("{}")) { - return nil - } - - // This is fairly tricky, and it's not clear that it is needed. - return errors.New("TODO: UnmarshalMessageSetJSON not yet implemented") -} - -// A global registry of types that can be used in a MessageSet. - -var messageSetMap = make(map[int32]messageSetDesc) - -type messageSetDesc struct { - t reflect.Type // pointer to struct - name string -} - -// RegisterMessageSetType is called from the generated code. -func RegisterMessageSetType(m Message, fieldNum int32, name string) { - messageSetMap[fieldNum] = messageSetDesc{ - t: reflect.TypeOf(m), - name: name, - } -} diff --git a/vendor/github.com/golang/protobuf/proto/pointer_reflect.go b/vendor/github.com/golang/protobuf/proto/pointer_reflect.go deleted file mode 100644 index fb512e2..0000000 --- a/vendor/github.com/golang/protobuf/proto/pointer_reflect.go +++ /dev/null @@ -1,484 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2012 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// +build appengine js - -// This file contains an implementation of proto field accesses using package reflect. -// It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can -// be used on App Engine. - -package proto - -import ( - "math" - "reflect" -) - -// A structPointer is a pointer to a struct. -type structPointer struct { - v reflect.Value -} - -// toStructPointer returns a structPointer equivalent to the given reflect value. -// The reflect value must itself be a pointer to a struct. -func toStructPointer(v reflect.Value) structPointer { - return structPointer{v} -} - -// IsNil reports whether p is nil. -func structPointer_IsNil(p structPointer) bool { - return p.v.IsNil() -} - -// Interface returns the struct pointer as an interface value. -func structPointer_Interface(p structPointer, _ reflect.Type) interface{} { - return p.v.Interface() -} - -// A field identifies a field in a struct, accessible from a structPointer. -// In this implementation, a field is identified by the sequence of field indices -// passed to reflect's FieldByIndex. -type field []int - -// toField returns a field equivalent to the given reflect field. -func toField(f *reflect.StructField) field { - return f.Index -} - -// invalidField is an invalid field identifier. -var invalidField = field(nil) - -// IsValid reports whether the field identifier is valid. -func (f field) IsValid() bool { return f != nil } - -// field returns the given field in the struct as a reflect value. -func structPointer_field(p structPointer, f field) reflect.Value { - // Special case: an extension map entry with a value of type T - // passes a *T to the struct-handling code with a zero field, - // expecting that it will be treated as equivalent to *struct{ X T }, - // which has the same memory layout. We have to handle that case - // specially, because reflect will panic if we call FieldByIndex on a - // non-struct. - if f == nil { - return p.v.Elem() - } - - return p.v.Elem().FieldByIndex(f) -} - -// ifield returns the given field in the struct as an interface value. -func structPointer_ifield(p structPointer, f field) interface{} { - return structPointer_field(p, f).Addr().Interface() -} - -// Bytes returns the address of a []byte field in the struct. -func structPointer_Bytes(p structPointer, f field) *[]byte { - return structPointer_ifield(p, f).(*[]byte) -} - -// BytesSlice returns the address of a [][]byte field in the struct. -func structPointer_BytesSlice(p structPointer, f field) *[][]byte { - return structPointer_ifield(p, f).(*[][]byte) -} - -// Bool returns the address of a *bool field in the struct. -func structPointer_Bool(p structPointer, f field) **bool { - return structPointer_ifield(p, f).(**bool) -} - -// BoolVal returns the address of a bool field in the struct. -func structPointer_BoolVal(p structPointer, f field) *bool { - return structPointer_ifield(p, f).(*bool) -} - -// BoolSlice returns the address of a []bool field in the struct. -func structPointer_BoolSlice(p structPointer, f field) *[]bool { - return structPointer_ifield(p, f).(*[]bool) -} - -// String returns the address of a *string field in the struct. -func structPointer_String(p structPointer, f field) **string { - return structPointer_ifield(p, f).(**string) -} - -// StringVal returns the address of a string field in the struct. -func structPointer_StringVal(p structPointer, f field) *string { - return structPointer_ifield(p, f).(*string) -} - -// StringSlice returns the address of a []string field in the struct. -func structPointer_StringSlice(p structPointer, f field) *[]string { - return structPointer_ifield(p, f).(*[]string) -} - -// Extensions returns the address of an extension map field in the struct. -func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions { - return structPointer_ifield(p, f).(*XXX_InternalExtensions) -} - -// ExtMap returns the address of an extension map field in the struct. -func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension { - return structPointer_ifield(p, f).(*map[int32]Extension) -} - -// NewAt returns the reflect.Value for a pointer to a field in the struct. -func structPointer_NewAt(p structPointer, f field, typ reflect.Type) reflect.Value { - return structPointer_field(p, f).Addr() -} - -// SetStructPointer writes a *struct field in the struct. -func structPointer_SetStructPointer(p structPointer, f field, q structPointer) { - structPointer_field(p, f).Set(q.v) -} - -// GetStructPointer reads a *struct field in the struct. -func structPointer_GetStructPointer(p structPointer, f field) structPointer { - return structPointer{structPointer_field(p, f)} -} - -// StructPointerSlice the address of a []*struct field in the struct. -func structPointer_StructPointerSlice(p structPointer, f field) structPointerSlice { - return structPointerSlice{structPointer_field(p, f)} -} - -// A structPointerSlice represents the address of a slice of pointers to structs -// (themselves messages or groups). That is, v.Type() is *[]*struct{...}. -type structPointerSlice struct { - v reflect.Value -} - -func (p structPointerSlice) Len() int { return p.v.Len() } -func (p structPointerSlice) Index(i int) structPointer { return structPointer{p.v.Index(i)} } -func (p structPointerSlice) Append(q structPointer) { - p.v.Set(reflect.Append(p.v, q.v)) -} - -var ( - int32Type = reflect.TypeOf(int32(0)) - uint32Type = reflect.TypeOf(uint32(0)) - float32Type = reflect.TypeOf(float32(0)) - int64Type = reflect.TypeOf(int64(0)) - uint64Type = reflect.TypeOf(uint64(0)) - float64Type = reflect.TypeOf(float64(0)) -) - -// A word32 represents a field of type *int32, *uint32, *float32, or *enum. -// That is, v.Type() is *int32, *uint32, *float32, or *enum and v is assignable. -type word32 struct { - v reflect.Value -} - -// IsNil reports whether p is nil. -func word32_IsNil(p word32) bool { - return p.v.IsNil() -} - -// Set sets p to point at a newly allocated word with bits set to x. -func word32_Set(p word32, o *Buffer, x uint32) { - t := p.v.Type().Elem() - switch t { - case int32Type: - if len(o.int32s) == 0 { - o.int32s = make([]int32, uint32PoolSize) - } - o.int32s[0] = int32(x) - p.v.Set(reflect.ValueOf(&o.int32s[0])) - o.int32s = o.int32s[1:] - return - case uint32Type: - if len(o.uint32s) == 0 { - o.uint32s = make([]uint32, uint32PoolSize) - } - o.uint32s[0] = x - p.v.Set(reflect.ValueOf(&o.uint32s[0])) - o.uint32s = o.uint32s[1:] - return - case float32Type: - if len(o.float32s) == 0 { - o.float32s = make([]float32, uint32PoolSize) - } - o.float32s[0] = math.Float32frombits(x) - p.v.Set(reflect.ValueOf(&o.float32s[0])) - o.float32s = o.float32s[1:] - return - } - - // must be enum - p.v.Set(reflect.New(t)) - p.v.Elem().SetInt(int64(int32(x))) -} - -// Get gets the bits pointed at by p, as a uint32. -func word32_Get(p word32) uint32 { - elem := p.v.Elem() - switch elem.Kind() { - case reflect.Int32: - return uint32(elem.Int()) - case reflect.Uint32: - return uint32(elem.Uint()) - case reflect.Float32: - return math.Float32bits(float32(elem.Float())) - } - panic("unreachable") -} - -// Word32 returns a reference to a *int32, *uint32, *float32, or *enum field in the struct. -func structPointer_Word32(p structPointer, f field) word32 { - return word32{structPointer_field(p, f)} -} - -// A word32Val represents a field of type int32, uint32, float32, or enum. -// That is, v.Type() is int32, uint32, float32, or enum and v is assignable. -type word32Val struct { - v reflect.Value -} - -// Set sets *p to x. -func word32Val_Set(p word32Val, x uint32) { - switch p.v.Type() { - case int32Type: - p.v.SetInt(int64(x)) - return - case uint32Type: - p.v.SetUint(uint64(x)) - return - case float32Type: - p.v.SetFloat(float64(math.Float32frombits(x))) - return - } - - // must be enum - p.v.SetInt(int64(int32(x))) -} - -// Get gets the bits pointed at by p, as a uint32. -func word32Val_Get(p word32Val) uint32 { - elem := p.v - switch elem.Kind() { - case reflect.Int32: - return uint32(elem.Int()) - case reflect.Uint32: - return uint32(elem.Uint()) - case reflect.Float32: - return math.Float32bits(float32(elem.Float())) - } - panic("unreachable") -} - -// Word32Val returns a reference to a int32, uint32, float32, or enum field in the struct. -func structPointer_Word32Val(p structPointer, f field) word32Val { - return word32Val{structPointer_field(p, f)} -} - -// A word32Slice is a slice of 32-bit values. -// That is, v.Type() is []int32, []uint32, []float32, or []enum. -type word32Slice struct { - v reflect.Value -} - -func (p word32Slice) Append(x uint32) { - n, m := p.v.Len(), p.v.Cap() - if n < m { - p.v.SetLen(n + 1) - } else { - t := p.v.Type().Elem() - p.v.Set(reflect.Append(p.v, reflect.Zero(t))) - } - elem := p.v.Index(n) - switch elem.Kind() { - case reflect.Int32: - elem.SetInt(int64(int32(x))) - case reflect.Uint32: - elem.SetUint(uint64(x)) - case reflect.Float32: - elem.SetFloat(float64(math.Float32frombits(x))) - } -} - -func (p word32Slice) Len() int { - return p.v.Len() -} - -func (p word32Slice) Index(i int) uint32 { - elem := p.v.Index(i) - switch elem.Kind() { - case reflect.Int32: - return uint32(elem.Int()) - case reflect.Uint32: - return uint32(elem.Uint()) - case reflect.Float32: - return math.Float32bits(float32(elem.Float())) - } - panic("unreachable") -} - -// Word32Slice returns a reference to a []int32, []uint32, []float32, or []enum field in the struct. -func structPointer_Word32Slice(p structPointer, f field) word32Slice { - return word32Slice{structPointer_field(p, f)} -} - -// word64 is like word32 but for 64-bit values. -type word64 struct { - v reflect.Value -} - -func word64_Set(p word64, o *Buffer, x uint64) { - t := p.v.Type().Elem() - switch t { - case int64Type: - if len(o.int64s) == 0 { - o.int64s = make([]int64, uint64PoolSize) - } - o.int64s[0] = int64(x) - p.v.Set(reflect.ValueOf(&o.int64s[0])) - o.int64s = o.int64s[1:] - return - case uint64Type: - if len(o.uint64s) == 0 { - o.uint64s = make([]uint64, uint64PoolSize) - } - o.uint64s[0] = x - p.v.Set(reflect.ValueOf(&o.uint64s[0])) - o.uint64s = o.uint64s[1:] - return - case float64Type: - if len(o.float64s) == 0 { - o.float64s = make([]float64, uint64PoolSize) - } - o.float64s[0] = math.Float64frombits(x) - p.v.Set(reflect.ValueOf(&o.float64s[0])) - o.float64s = o.float64s[1:] - return - } - panic("unreachable") -} - -func word64_IsNil(p word64) bool { - return p.v.IsNil() -} - -func word64_Get(p word64) uint64 { - elem := p.v.Elem() - switch elem.Kind() { - case reflect.Int64: - return uint64(elem.Int()) - case reflect.Uint64: - return elem.Uint() - case reflect.Float64: - return math.Float64bits(elem.Float()) - } - panic("unreachable") -} - -func structPointer_Word64(p structPointer, f field) word64 { - return word64{structPointer_field(p, f)} -} - -// word64Val is like word32Val but for 64-bit values. -type word64Val struct { - v reflect.Value -} - -func word64Val_Set(p word64Val, o *Buffer, x uint64) { - switch p.v.Type() { - case int64Type: - p.v.SetInt(int64(x)) - return - case uint64Type: - p.v.SetUint(x) - return - case float64Type: - p.v.SetFloat(math.Float64frombits(x)) - return - } - panic("unreachable") -} - -func word64Val_Get(p word64Val) uint64 { - elem := p.v - switch elem.Kind() { - case reflect.Int64: - return uint64(elem.Int()) - case reflect.Uint64: - return elem.Uint() - case reflect.Float64: - return math.Float64bits(elem.Float()) - } - panic("unreachable") -} - -func structPointer_Word64Val(p structPointer, f field) word64Val { - return word64Val{structPointer_field(p, f)} -} - -type word64Slice struct { - v reflect.Value -} - -func (p word64Slice) Append(x uint64) { - n, m := p.v.Len(), p.v.Cap() - if n < m { - p.v.SetLen(n + 1) - } else { - t := p.v.Type().Elem() - p.v.Set(reflect.Append(p.v, reflect.Zero(t))) - } - elem := p.v.Index(n) - switch elem.Kind() { - case reflect.Int64: - elem.SetInt(int64(int64(x))) - case reflect.Uint64: - elem.SetUint(uint64(x)) - case reflect.Float64: - elem.SetFloat(float64(math.Float64frombits(x))) - } -} - -func (p word64Slice) Len() int { - return p.v.Len() -} - -func (p word64Slice) Index(i int) uint64 { - elem := p.v.Index(i) - switch elem.Kind() { - case reflect.Int64: - return uint64(elem.Int()) - case reflect.Uint64: - return uint64(elem.Uint()) - case reflect.Float64: - return math.Float64bits(float64(elem.Float())) - } - panic("unreachable") -} - -func structPointer_Word64Slice(p structPointer, f field) word64Slice { - return word64Slice{structPointer_field(p, f)} -} diff --git a/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go b/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go deleted file mode 100644 index 6b5567d..0000000 --- a/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go +++ /dev/null @@ -1,270 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2012 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// +build !appengine,!js - -// This file contains the implementation of the proto field accesses using package unsafe. - -package proto - -import ( - "reflect" - "unsafe" -) - -// NOTE: These type_Foo functions would more idiomatically be methods, -// but Go does not allow methods on pointer types, and we must preserve -// some pointer type for the garbage collector. We use these -// funcs with clunky names as our poor approximation to methods. -// -// An alternative would be -// type structPointer struct { p unsafe.Pointer } -// but that does not registerize as well. - -// A structPointer is a pointer to a struct. -type structPointer unsafe.Pointer - -// toStructPointer returns a structPointer equivalent to the given reflect value. -func toStructPointer(v reflect.Value) structPointer { - return structPointer(unsafe.Pointer(v.Pointer())) -} - -// IsNil reports whether p is nil. -func structPointer_IsNil(p structPointer) bool { - return p == nil -} - -// Interface returns the struct pointer, assumed to have element type t, -// as an interface value. -func structPointer_Interface(p structPointer, t reflect.Type) interface{} { - return reflect.NewAt(t, unsafe.Pointer(p)).Interface() -} - -// A field identifies a field in a struct, accessible from a structPointer. -// In this implementation, a field is identified by its byte offset from the start of the struct. -type field uintptr - -// toField returns a field equivalent to the given reflect field. -func toField(f *reflect.StructField) field { - return field(f.Offset) -} - -// invalidField is an invalid field identifier. -const invalidField = ^field(0) - -// IsValid reports whether the field identifier is valid. -func (f field) IsValid() bool { - return f != ^field(0) -} - -// Bytes returns the address of a []byte field in the struct. -func structPointer_Bytes(p structPointer, f field) *[]byte { - return (*[]byte)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// BytesSlice returns the address of a [][]byte field in the struct. -func structPointer_BytesSlice(p structPointer, f field) *[][]byte { - return (*[][]byte)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// Bool returns the address of a *bool field in the struct. -func structPointer_Bool(p structPointer, f field) **bool { - return (**bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// BoolVal returns the address of a bool field in the struct. -func structPointer_BoolVal(p structPointer, f field) *bool { - return (*bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// BoolSlice returns the address of a []bool field in the struct. -func structPointer_BoolSlice(p structPointer, f field) *[]bool { - return (*[]bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// String returns the address of a *string field in the struct. -func structPointer_String(p structPointer, f field) **string { - return (**string)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// StringVal returns the address of a string field in the struct. -func structPointer_StringVal(p structPointer, f field) *string { - return (*string)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// StringSlice returns the address of a []string field in the struct. -func structPointer_StringSlice(p structPointer, f field) *[]string { - return (*[]string)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// ExtMap returns the address of an extension map field in the struct. -func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions { - return (*XXX_InternalExtensions)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension { - return (*map[int32]Extension)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// NewAt returns the reflect.Value for a pointer to a field in the struct. -func structPointer_NewAt(p structPointer, f field, typ reflect.Type) reflect.Value { - return reflect.NewAt(typ, unsafe.Pointer(uintptr(p)+uintptr(f))) -} - -// SetStructPointer writes a *struct field in the struct. -func structPointer_SetStructPointer(p structPointer, f field, q structPointer) { - *(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) = q -} - -// GetStructPointer reads a *struct field in the struct. -func structPointer_GetStructPointer(p structPointer, f field) structPointer { - return *(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// StructPointerSlice the address of a []*struct field in the struct. -func structPointer_StructPointerSlice(p structPointer, f field) *structPointerSlice { - return (*structPointerSlice)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// A structPointerSlice represents a slice of pointers to structs (themselves submessages or groups). -type structPointerSlice []structPointer - -func (v *structPointerSlice) Len() int { return len(*v) } -func (v *structPointerSlice) Index(i int) structPointer { return (*v)[i] } -func (v *structPointerSlice) Append(p structPointer) { *v = append(*v, p) } - -// A word32 is the address of a "pointer to 32-bit value" field. -type word32 **uint32 - -// IsNil reports whether *v is nil. -func word32_IsNil(p word32) bool { - return *p == nil -} - -// Set sets *v to point at a newly allocated word set to x. -func word32_Set(p word32, o *Buffer, x uint32) { - if len(o.uint32s) == 0 { - o.uint32s = make([]uint32, uint32PoolSize) - } - o.uint32s[0] = x - *p = &o.uint32s[0] - o.uint32s = o.uint32s[1:] -} - -// Get gets the value pointed at by *v. -func word32_Get(p word32) uint32 { - return **p -} - -// Word32 returns the address of a *int32, *uint32, *float32, or *enum field in the struct. -func structPointer_Word32(p structPointer, f field) word32 { - return word32((**uint32)(unsafe.Pointer(uintptr(p) + uintptr(f)))) -} - -// A word32Val is the address of a 32-bit value field. -type word32Val *uint32 - -// Set sets *p to x. -func word32Val_Set(p word32Val, x uint32) { - *p = x -} - -// Get gets the value pointed at by p. -func word32Val_Get(p word32Val) uint32 { - return *p -} - -// Word32Val returns the address of a *int32, *uint32, *float32, or *enum field in the struct. -func structPointer_Word32Val(p structPointer, f field) word32Val { - return word32Val((*uint32)(unsafe.Pointer(uintptr(p) + uintptr(f)))) -} - -// A word32Slice is a slice of 32-bit values. -type word32Slice []uint32 - -func (v *word32Slice) Append(x uint32) { *v = append(*v, x) } -func (v *word32Slice) Len() int { return len(*v) } -func (v *word32Slice) Index(i int) uint32 { return (*v)[i] } - -// Word32Slice returns the address of a []int32, []uint32, []float32, or []enum field in the struct. -func structPointer_Word32Slice(p structPointer, f field) *word32Slice { - return (*word32Slice)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// word64 is like word32 but for 64-bit values. -type word64 **uint64 - -func word64_Set(p word64, o *Buffer, x uint64) { - if len(o.uint64s) == 0 { - o.uint64s = make([]uint64, uint64PoolSize) - } - o.uint64s[0] = x - *p = &o.uint64s[0] - o.uint64s = o.uint64s[1:] -} - -func word64_IsNil(p word64) bool { - return *p == nil -} - -func word64_Get(p word64) uint64 { - return **p -} - -func structPointer_Word64(p structPointer, f field) word64 { - return word64((**uint64)(unsafe.Pointer(uintptr(p) + uintptr(f)))) -} - -// word64Val is like word32Val but for 64-bit values. -type word64Val *uint64 - -func word64Val_Set(p word64Val, o *Buffer, x uint64) { - *p = x -} - -func word64Val_Get(p word64Val) uint64 { - return *p -} - -func structPointer_Word64Val(p structPointer, f field) word64Val { - return word64Val((*uint64)(unsafe.Pointer(uintptr(p) + uintptr(f)))) -} - -// word64Slice is like word32Slice but for 64-bit values. -type word64Slice []uint64 - -func (v *word64Slice) Append(x uint64) { *v = append(*v, x) } -func (v *word64Slice) Len() int { return len(*v) } -func (v *word64Slice) Index(i int) uint64 { return (*v)[i] } - -func structPointer_Word64Slice(p structPointer, f field) *word64Slice { - return (*word64Slice)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} diff --git a/vendor/github.com/golang/protobuf/proto/properties.go b/vendor/github.com/golang/protobuf/proto/properties.go deleted file mode 100644 index ec2289c..0000000 --- a/vendor/github.com/golang/protobuf/proto/properties.go +++ /dev/null @@ -1,872 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -/* - * Routines for encoding data into the wire format for protocol buffers. - */ - -import ( - "fmt" - "log" - "os" - "reflect" - "sort" - "strconv" - "strings" - "sync" -) - -const debug bool = false - -// Constants that identify the encoding of a value on the wire. -const ( - WireVarint = 0 - WireFixed64 = 1 - WireBytes = 2 - WireStartGroup = 3 - WireEndGroup = 4 - WireFixed32 = 5 -) - -const startSize = 10 // initial slice/string sizes - -// Encoders are defined in encode.go -// An encoder outputs the full representation of a field, including its -// tag and encoder type. -type encoder func(p *Buffer, prop *Properties, base structPointer) error - -// A valueEncoder encodes a single integer in a particular encoding. -type valueEncoder func(o *Buffer, x uint64) error - -// Sizers are defined in encode.go -// A sizer returns the encoded size of a field, including its tag and encoder -// type. -type sizer func(prop *Properties, base structPointer) int - -// A valueSizer returns the encoded size of a single integer in a particular -// encoding. -type valueSizer func(x uint64) int - -// Decoders are defined in decode.go -// A decoder creates a value from its wire representation. -// Unrecognized subelements are saved in unrec. -type decoder func(p *Buffer, prop *Properties, base structPointer) error - -// A valueDecoder decodes a single integer in a particular encoding. -type valueDecoder func(o *Buffer) (x uint64, err error) - -// A oneofMarshaler does the marshaling for all oneof fields in a message. -type oneofMarshaler func(Message, *Buffer) error - -// A oneofUnmarshaler does the unmarshaling for a oneof field in a message. -type oneofUnmarshaler func(Message, int, int, *Buffer) (bool, error) - -// A oneofSizer does the sizing for all oneof fields in a message. -type oneofSizer func(Message) int - -// tagMap is an optimization over map[int]int for typical protocol buffer -// use-cases. Encoded protocol buffers are often in tag order with small tag -// numbers. -type tagMap struct { - fastTags []int - slowTags map[int]int -} - -// tagMapFastLimit is the upper bound on the tag number that will be stored in -// the tagMap slice rather than its map. -const tagMapFastLimit = 1024 - -func (p *tagMap) get(t int) (int, bool) { - if t > 0 && t < tagMapFastLimit { - if t >= len(p.fastTags) { - return 0, false - } - fi := p.fastTags[t] - return fi, fi >= 0 - } - fi, ok := p.slowTags[t] - return fi, ok -} - -func (p *tagMap) put(t int, fi int) { - if t > 0 && t < tagMapFastLimit { - for len(p.fastTags) < t+1 { - p.fastTags = append(p.fastTags, -1) - } - p.fastTags[t] = fi - return - } - if p.slowTags == nil { - p.slowTags = make(map[int]int) - } - p.slowTags[t] = fi -} - -// StructProperties represents properties for all the fields of a struct. -// decoderTags and decoderOrigNames should only be used by the decoder. -type StructProperties struct { - Prop []*Properties // properties for each field - reqCount int // required count - decoderTags tagMap // map from proto tag to struct field number - decoderOrigNames map[string]int // map from original name to struct field number - order []int // list of struct field numbers in tag order - unrecField field // field id of the XXX_unrecognized []byte field - extendable bool // is this an extendable proto - - oneofMarshaler oneofMarshaler - oneofUnmarshaler oneofUnmarshaler - oneofSizer oneofSizer - stype reflect.Type - - // OneofTypes contains information about the oneof fields in this message. - // It is keyed by the original name of a field. - OneofTypes map[string]*OneofProperties -} - -// OneofProperties represents information about a specific field in a oneof. -type OneofProperties struct { - Type reflect.Type // pointer to generated struct type for this oneof field - Field int // struct field number of the containing oneof in the message - Prop *Properties -} - -// Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec. -// See encode.go, (*Buffer).enc_struct. - -func (sp *StructProperties) Len() int { return len(sp.order) } -func (sp *StructProperties) Less(i, j int) bool { - return sp.Prop[sp.order[i]].Tag < sp.Prop[sp.order[j]].Tag -} -func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order[j], sp.order[i] } - -// Properties represents the protocol-specific behavior of a single struct field. -type Properties struct { - Name string // name of the field, for error messages - OrigName string // original name before protocol compiler (always set) - JSONName string // name to use for JSON; determined by protoc - Wire string - WireType int - Tag int - Required bool - Optional bool - Repeated bool - Packed bool // relevant for repeated primitives only - Enum string // set for enum types only - proto3 bool // whether this is known to be a proto3 field; set for []byte only - oneof bool // whether this is a oneof field - - Default string // default value - HasDefault bool // whether an explicit default was provided - def_uint64 uint64 - - enc encoder - valEnc valueEncoder // set for bool and numeric types only - field field - tagcode []byte // encoding of EncodeVarint((Tag<<3)|WireType) - tagbuf [8]byte - stype reflect.Type // set for struct types only - sprop *StructProperties // set for struct types only - isMarshaler bool - isUnmarshaler bool - - mtype reflect.Type // set for map types only - mkeyprop *Properties // set for map types only - mvalprop *Properties // set for map types only - - size sizer - valSize valueSizer // set for bool and numeric types only - - dec decoder - valDec valueDecoder // set for bool and numeric types only - - // If this is a packable field, this will be the decoder for the packed version of the field. - packedDec decoder -} - -// String formats the properties in the protobuf struct field tag style. -func (p *Properties) String() string { - s := p.Wire - s = "," - s += strconv.Itoa(p.Tag) - if p.Required { - s += ",req" - } - if p.Optional { - s += ",opt" - } - if p.Repeated { - s += ",rep" - } - if p.Packed { - s += ",packed" - } - s += ",name=" + p.OrigName - if p.JSONName != p.OrigName { - s += ",json=" + p.JSONName - } - if p.proto3 { - s += ",proto3" - } - if p.oneof { - s += ",oneof" - } - if len(p.Enum) > 0 { - s += ",enum=" + p.Enum - } - if p.HasDefault { - s += ",def=" + p.Default - } - return s -} - -// Parse populates p by parsing a string in the protobuf struct field tag style. -func (p *Properties) Parse(s string) { - // "bytes,49,opt,name=foo,def=hello!" - fields := strings.Split(s, ",") // breaks def=, but handled below. - if len(fields) < 2 { - fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s) - return - } - - p.Wire = fields[0] - switch p.Wire { - case "varint": - p.WireType = WireVarint - p.valEnc = (*Buffer).EncodeVarint - p.valDec = (*Buffer).DecodeVarint - p.valSize = sizeVarint - case "fixed32": - p.WireType = WireFixed32 - p.valEnc = (*Buffer).EncodeFixed32 - p.valDec = (*Buffer).DecodeFixed32 - p.valSize = sizeFixed32 - case "fixed64": - p.WireType = WireFixed64 - p.valEnc = (*Buffer).EncodeFixed64 - p.valDec = (*Buffer).DecodeFixed64 - p.valSize = sizeFixed64 - case "zigzag32": - p.WireType = WireVarint - p.valEnc = (*Buffer).EncodeZigzag32 - p.valDec = (*Buffer).DecodeZigzag32 - p.valSize = sizeZigzag32 - case "zigzag64": - p.WireType = WireVarint - p.valEnc = (*Buffer).EncodeZigzag64 - p.valDec = (*Buffer).DecodeZigzag64 - p.valSize = sizeZigzag64 - case "bytes", "group": - p.WireType = WireBytes - // no numeric converter for non-numeric types - default: - fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s) - return - } - - var err error - p.Tag, err = strconv.Atoi(fields[1]) - if err != nil { - return - } - - for i := 2; i < len(fields); i++ { - f := fields[i] - switch { - case f == "req": - p.Required = true - case f == "opt": - p.Optional = true - case f == "rep": - p.Repeated = true - case f == "packed": - p.Packed = true - case strings.HasPrefix(f, "name="): - p.OrigName = f[5:] - case strings.HasPrefix(f, "json="): - p.JSONName = f[5:] - case strings.HasPrefix(f, "enum="): - p.Enum = f[5:] - case f == "proto3": - p.proto3 = true - case f == "oneof": - p.oneof = true - case strings.HasPrefix(f, "def="): - p.HasDefault = true - p.Default = f[4:] // rest of string - if i+1 < len(fields) { - // Commas aren't escaped, and def is always last. - p.Default += "," + strings.Join(fields[i+1:], ",") - break - } - } - } -} - -func logNoSliceEnc(t1, t2 reflect.Type) { - fmt.Fprintf(os.Stderr, "proto: no slice oenc for %T = []%T\n", t1, t2) -} - -var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem() - -// Initialize the fields for encoding and decoding. -func (p *Properties) setEncAndDec(typ reflect.Type, f *reflect.StructField, lockGetProp bool) { - p.enc = nil - p.dec = nil - p.size = nil - - switch t1 := typ; t1.Kind() { - default: - fmt.Fprintf(os.Stderr, "proto: no coders for %v\n", t1) - - // proto3 scalar types - - case reflect.Bool: - p.enc = (*Buffer).enc_proto3_bool - p.dec = (*Buffer).dec_proto3_bool - p.size = size_proto3_bool - case reflect.Int32: - p.enc = (*Buffer).enc_proto3_int32 - p.dec = (*Buffer).dec_proto3_int32 - p.size = size_proto3_int32 - case reflect.Uint32: - p.enc = (*Buffer).enc_proto3_uint32 - p.dec = (*Buffer).dec_proto3_int32 // can reuse - p.size = size_proto3_uint32 - case reflect.Int64, reflect.Uint64: - p.enc = (*Buffer).enc_proto3_int64 - p.dec = (*Buffer).dec_proto3_int64 - p.size = size_proto3_int64 - case reflect.Float32: - p.enc = (*Buffer).enc_proto3_uint32 // can just treat them as bits - p.dec = (*Buffer).dec_proto3_int32 - p.size = size_proto3_uint32 - case reflect.Float64: - p.enc = (*Buffer).enc_proto3_int64 // can just treat them as bits - p.dec = (*Buffer).dec_proto3_int64 - p.size = size_proto3_int64 - case reflect.String: - p.enc = (*Buffer).enc_proto3_string - p.dec = (*Buffer).dec_proto3_string - p.size = size_proto3_string - - case reflect.Ptr: - switch t2 := t1.Elem(); t2.Kind() { - default: - fmt.Fprintf(os.Stderr, "proto: no encoder function for %v -> %v\n", t1, t2) - break - case reflect.Bool: - p.enc = (*Buffer).enc_bool - p.dec = (*Buffer).dec_bool - p.size = size_bool - case reflect.Int32: - p.enc = (*Buffer).enc_int32 - p.dec = (*Buffer).dec_int32 - p.size = size_int32 - case reflect.Uint32: - p.enc = (*Buffer).enc_uint32 - p.dec = (*Buffer).dec_int32 // can reuse - p.size = size_uint32 - case reflect.Int64, reflect.Uint64: - p.enc = (*Buffer).enc_int64 - p.dec = (*Buffer).dec_int64 - p.size = size_int64 - case reflect.Float32: - p.enc = (*Buffer).enc_uint32 // can just treat them as bits - p.dec = (*Buffer).dec_int32 - p.size = size_uint32 - case reflect.Float64: - p.enc = (*Buffer).enc_int64 // can just treat them as bits - p.dec = (*Buffer).dec_int64 - p.size = size_int64 - case reflect.String: - p.enc = (*Buffer).enc_string - p.dec = (*Buffer).dec_string - p.size = size_string - case reflect.Struct: - p.stype = t1.Elem() - p.isMarshaler = isMarshaler(t1) - p.isUnmarshaler = isUnmarshaler(t1) - if p.Wire == "bytes" { - p.enc = (*Buffer).enc_struct_message - p.dec = (*Buffer).dec_struct_message - p.size = size_struct_message - } else { - p.enc = (*Buffer).enc_struct_group - p.dec = (*Buffer).dec_struct_group - p.size = size_struct_group - } - } - - case reflect.Slice: - switch t2 := t1.Elem(); t2.Kind() { - default: - logNoSliceEnc(t1, t2) - break - case reflect.Bool: - if p.Packed { - p.enc = (*Buffer).enc_slice_packed_bool - p.size = size_slice_packed_bool - } else { - p.enc = (*Buffer).enc_slice_bool - p.size = size_slice_bool - } - p.dec = (*Buffer).dec_slice_bool - p.packedDec = (*Buffer).dec_slice_packed_bool - case reflect.Int32: - if p.Packed { - p.enc = (*Buffer).enc_slice_packed_int32 - p.size = size_slice_packed_int32 - } else { - p.enc = (*Buffer).enc_slice_int32 - p.size = size_slice_int32 - } - p.dec = (*Buffer).dec_slice_int32 - p.packedDec = (*Buffer).dec_slice_packed_int32 - case reflect.Uint32: - if p.Packed { - p.enc = (*Buffer).enc_slice_packed_uint32 - p.size = size_slice_packed_uint32 - } else { - p.enc = (*Buffer).enc_slice_uint32 - p.size = size_slice_uint32 - } - p.dec = (*Buffer).dec_slice_int32 - p.packedDec = (*Buffer).dec_slice_packed_int32 - case reflect.Int64, reflect.Uint64: - if p.Packed { - p.enc = (*Buffer).enc_slice_packed_int64 - p.size = size_slice_packed_int64 - } else { - p.enc = (*Buffer).enc_slice_int64 - p.size = size_slice_int64 - } - p.dec = (*Buffer).dec_slice_int64 - p.packedDec = (*Buffer).dec_slice_packed_int64 - case reflect.Uint8: - p.dec = (*Buffer).dec_slice_byte - if p.proto3 { - p.enc = (*Buffer).enc_proto3_slice_byte - p.size = size_proto3_slice_byte - } else { - p.enc = (*Buffer).enc_slice_byte - p.size = size_slice_byte - } - case reflect.Float32, reflect.Float64: - switch t2.Bits() { - case 32: - // can just treat them as bits - if p.Packed { - p.enc = (*Buffer).enc_slice_packed_uint32 - p.size = size_slice_packed_uint32 - } else { - p.enc = (*Buffer).enc_slice_uint32 - p.size = size_slice_uint32 - } - p.dec = (*Buffer).dec_slice_int32 - p.packedDec = (*Buffer).dec_slice_packed_int32 - case 64: - // can just treat them as bits - if p.Packed { - p.enc = (*Buffer).enc_slice_packed_int64 - p.size = size_slice_packed_int64 - } else { - p.enc = (*Buffer).enc_slice_int64 - p.size = size_slice_int64 - } - p.dec = (*Buffer).dec_slice_int64 - p.packedDec = (*Buffer).dec_slice_packed_int64 - default: - logNoSliceEnc(t1, t2) - break - } - case reflect.String: - p.enc = (*Buffer).enc_slice_string - p.dec = (*Buffer).dec_slice_string - p.size = size_slice_string - case reflect.Ptr: - switch t3 := t2.Elem(); t3.Kind() { - default: - fmt.Fprintf(os.Stderr, "proto: no ptr oenc for %T -> %T -> %T\n", t1, t2, t3) - break - case reflect.Struct: - p.stype = t2.Elem() - p.isMarshaler = isMarshaler(t2) - p.isUnmarshaler = isUnmarshaler(t2) - if p.Wire == "bytes" { - p.enc = (*Buffer).enc_slice_struct_message - p.dec = (*Buffer).dec_slice_struct_message - p.size = size_slice_struct_message - } else { - p.enc = (*Buffer).enc_slice_struct_group - p.dec = (*Buffer).dec_slice_struct_group - p.size = size_slice_struct_group - } - } - case reflect.Slice: - switch t2.Elem().Kind() { - default: - fmt.Fprintf(os.Stderr, "proto: no slice elem oenc for %T -> %T -> %T\n", t1, t2, t2.Elem()) - break - case reflect.Uint8: - p.enc = (*Buffer).enc_slice_slice_byte - p.dec = (*Buffer).dec_slice_slice_byte - p.size = size_slice_slice_byte - } - } - - case reflect.Map: - p.enc = (*Buffer).enc_new_map - p.dec = (*Buffer).dec_new_map - p.size = size_new_map - - p.mtype = t1 - p.mkeyprop = &Properties{} - p.mkeyprop.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp) - p.mvalprop = &Properties{} - vtype := p.mtype.Elem() - if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice { - // The value type is not a message (*T) or bytes ([]byte), - // so we need encoders for the pointer to this type. - vtype = reflect.PtrTo(vtype) - } - p.mvalprop.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp) - } - - // precalculate tag code - wire := p.WireType - if p.Packed { - wire = WireBytes - } - x := uint32(p.Tag)<<3 | uint32(wire) - i := 0 - for i = 0; x > 127; i++ { - p.tagbuf[i] = 0x80 | uint8(x&0x7F) - x >>= 7 - } - p.tagbuf[i] = uint8(x) - p.tagcode = p.tagbuf[0 : i+1] - - if p.stype != nil { - if lockGetProp { - p.sprop = GetProperties(p.stype) - } else { - p.sprop = getPropertiesLocked(p.stype) - } - } -} - -var ( - marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() - unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem() -) - -// isMarshaler reports whether type t implements Marshaler. -func isMarshaler(t reflect.Type) bool { - // We're checking for (likely) pointer-receiver methods - // so if t is not a pointer, something is very wrong. - // The calls above only invoke isMarshaler on pointer types. - if t.Kind() != reflect.Ptr { - panic("proto: misuse of isMarshaler") - } - return t.Implements(marshalerType) -} - -// isUnmarshaler reports whether type t implements Unmarshaler. -func isUnmarshaler(t reflect.Type) bool { - // We're checking for (likely) pointer-receiver methods - // so if t is not a pointer, something is very wrong. - // The calls above only invoke isUnmarshaler on pointer types. - if t.Kind() != reflect.Ptr { - panic("proto: misuse of isUnmarshaler") - } - return t.Implements(unmarshalerType) -} - -// Init populates the properties from a protocol buffer struct tag. -func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) { - p.init(typ, name, tag, f, true) -} - -func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructField, lockGetProp bool) { - // "bytes,49,opt,def=hello!" - p.Name = name - p.OrigName = name - if f != nil { - p.field = toField(f) - } - if tag == "" { - return - } - p.Parse(tag) - p.setEncAndDec(typ, f, lockGetProp) -} - -var ( - propertiesMu sync.RWMutex - propertiesMap = make(map[reflect.Type]*StructProperties) -) - -// GetProperties returns the list of properties for the type represented by t. -// t must represent a generated struct type of a protocol message. -func GetProperties(t reflect.Type) *StructProperties { - if t.Kind() != reflect.Struct { - panic("proto: type must have kind struct") - } - - // Most calls to GetProperties in a long-running program will be - // retrieving details for types we have seen before. - propertiesMu.RLock() - sprop, ok := propertiesMap[t] - propertiesMu.RUnlock() - if ok { - if collectStats { - stats.Chit++ - } - return sprop - } - - propertiesMu.Lock() - sprop = getPropertiesLocked(t) - propertiesMu.Unlock() - return sprop -} - -// getPropertiesLocked requires that propertiesMu is held. -func getPropertiesLocked(t reflect.Type) *StructProperties { - if prop, ok := propertiesMap[t]; ok { - if collectStats { - stats.Chit++ - } - return prop - } - if collectStats { - stats.Cmiss++ - } - - prop := new(StructProperties) - // in case of recursive protos, fill this in now. - propertiesMap[t] = prop - - // build properties - prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType) || - reflect.PtrTo(t).Implements(extendableProtoV1Type) - prop.unrecField = invalidField - prop.Prop = make([]*Properties, t.NumField()) - prop.order = make([]int, t.NumField()) - - for i := 0; i < t.NumField(); i++ { - f := t.Field(i) - p := new(Properties) - name := f.Name - p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false) - - if f.Name == "XXX_InternalExtensions" { // special case - p.enc = (*Buffer).enc_exts - p.dec = nil // not needed - p.size = size_exts - } else if f.Name == "XXX_extensions" { // special case - p.enc = (*Buffer).enc_map - p.dec = nil // not needed - p.size = size_map - } else if f.Name == "XXX_unrecognized" { // special case - prop.unrecField = toField(&f) - } - oneof := f.Tag.Get("protobuf_oneof") // special case - if oneof != "" { - // Oneof fields don't use the traditional protobuf tag. - p.OrigName = oneof - } - prop.Prop[i] = p - prop.order[i] = i - if debug { - print(i, " ", f.Name, " ", t.String(), " ") - if p.Tag > 0 { - print(p.String()) - } - print("\n") - } - if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") && oneof == "" { - fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]") - } - } - - // Re-order prop.order. - sort.Sort(prop) - - type oneofMessage interface { - XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{}) - } - if om, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok { - var oots []interface{} - prop.oneofMarshaler, prop.oneofUnmarshaler, prop.oneofSizer, oots = om.XXX_OneofFuncs() - prop.stype = t - - // Interpret oneof metadata. - prop.OneofTypes = make(map[string]*OneofProperties) - for _, oot := range oots { - oop := &OneofProperties{ - Type: reflect.ValueOf(oot).Type(), // *T - Prop: new(Properties), - } - sft := oop.Type.Elem().Field(0) - oop.Prop.Name = sft.Name - oop.Prop.Parse(sft.Tag.Get("protobuf")) - // There will be exactly one interface field that - // this new value is assignable to. - for i := 0; i < t.NumField(); i++ { - f := t.Field(i) - if f.Type.Kind() != reflect.Interface { - continue - } - if !oop.Type.AssignableTo(f.Type) { - continue - } - oop.Field = i - break - } - prop.OneofTypes[oop.Prop.OrigName] = oop - } - } - - // build required counts - // build tags - reqCount := 0 - prop.decoderOrigNames = make(map[string]int) - for i, p := range prop.Prop { - if strings.HasPrefix(p.Name, "XXX_") { - // Internal fields should not appear in tags/origNames maps. - // They are handled specially when encoding and decoding. - continue - } - if p.Required { - reqCount++ - } - prop.decoderTags.put(p.Tag, i) - prop.decoderOrigNames[p.OrigName] = i - } - prop.reqCount = reqCount - - return prop -} - -// Return the Properties object for the x[0]'th field of the structure. -func propByIndex(t reflect.Type, x []int) *Properties { - if len(x) != 1 { - fmt.Fprintf(os.Stderr, "proto: field index dimension %d (not 1) for type %s\n", len(x), t) - return nil - } - prop := GetProperties(t) - return prop.Prop[x[0]] -} - -// Get the address and type of a pointer to a struct from an interface. -func getbase(pb Message) (t reflect.Type, b structPointer, err error) { - if pb == nil { - err = ErrNil - return - } - // get the reflect type of the pointer to the struct. - t = reflect.TypeOf(pb) - // get the address of the struct. - value := reflect.ValueOf(pb) - b = toStructPointer(value) - return -} - -// A global registry of enum types. -// The generated code will register the generated maps by calling RegisterEnum. - -var enumValueMaps = make(map[string]map[string]int32) - -// RegisterEnum is called from the generated code to install the enum descriptor -// maps into the global table to aid parsing text format protocol buffers. -func RegisterEnum(typeName string, unusedNameMap map[int32]string, valueMap map[string]int32) { - if _, ok := enumValueMaps[typeName]; ok { - panic("proto: duplicate enum registered: " + typeName) - } - enumValueMaps[typeName] = valueMap -} - -// EnumValueMap returns the mapping from names to integers of the -// enum type enumType, or a nil if not found. -func EnumValueMap(enumType string) map[string]int32 { - return enumValueMaps[enumType] -} - -// A registry of all linked message types. -// The string is a fully-qualified proto name ("pkg.Message"). -var ( - protoTypes = make(map[string]reflect.Type) - revProtoTypes = make(map[reflect.Type]string) -) - -// RegisterType is called from generated code and maps from the fully qualified -// proto name to the type (pointer to struct) of the protocol buffer. -func RegisterType(x Message, name string) { - if _, ok := protoTypes[name]; ok { - // TODO: Some day, make this a panic. - log.Printf("proto: duplicate proto type registered: %s", name) - return - } - t := reflect.TypeOf(x) - protoTypes[name] = t - revProtoTypes[t] = name -} - -// MessageName returns the fully-qualified proto name for the given message type. -func MessageName(x Message) string { - type xname interface { - XXX_MessageName() string - } - if m, ok := x.(xname); ok { - return m.XXX_MessageName() - } - return revProtoTypes[reflect.TypeOf(x)] -} - -// MessageType returns the message type (pointer to struct) for a named message. -func MessageType(name string) reflect.Type { return protoTypes[name] } - -// A registry of all linked proto files. -var ( - protoFiles = make(map[string][]byte) // file name => fileDescriptor -) - -// RegisterFile is called from generated code and maps from the -// full file name of a .proto file to its compressed FileDescriptorProto. -func RegisterFile(filename string, fileDescriptor []byte) { - protoFiles[filename] = fileDescriptor -} - -// FileDescriptor returns the compressed FileDescriptorProto for a .proto file. -func FileDescriptor(filename string) []byte { return protoFiles[filename] } diff --git a/vendor/github.com/golang/protobuf/proto/text.go b/vendor/github.com/golang/protobuf/proto/text.go deleted file mode 100644 index 965876b..0000000 --- a/vendor/github.com/golang/protobuf/proto/text.go +++ /dev/null @@ -1,854 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -// Functions for writing the text protocol buffer format. - -import ( - "bufio" - "bytes" - "encoding" - "errors" - "fmt" - "io" - "log" - "math" - "reflect" - "sort" - "strings" -) - -var ( - newline = []byte("\n") - spaces = []byte(" ") - gtNewline = []byte(">\n") - endBraceNewline = []byte("}\n") - backslashN = []byte{'\\', 'n'} - backslashR = []byte{'\\', 'r'} - backslashT = []byte{'\\', 't'} - backslashDQ = []byte{'\\', '"'} - backslashBS = []byte{'\\', '\\'} - posInf = []byte("inf") - negInf = []byte("-inf") - nan = []byte("nan") -) - -type writer interface { - io.Writer - WriteByte(byte) error -} - -// textWriter is an io.Writer that tracks its indentation level. -type textWriter struct { - ind int - complete bool // if the current position is a complete line - compact bool // whether to write out as a one-liner - w writer -} - -func (w *textWriter) WriteString(s string) (n int, err error) { - if !strings.Contains(s, "\n") { - if !w.compact && w.complete { - w.writeIndent() - } - w.complete = false - return io.WriteString(w.w, s) - } - // WriteString is typically called without newlines, so this - // codepath and its copy are rare. We copy to avoid - // duplicating all of Write's logic here. - return w.Write([]byte(s)) -} - -func (w *textWriter) Write(p []byte) (n int, err error) { - newlines := bytes.Count(p, newline) - if newlines == 0 { - if !w.compact && w.complete { - w.writeIndent() - } - n, err = w.w.Write(p) - w.complete = false - return n, err - } - - frags := bytes.SplitN(p, newline, newlines+1) - if w.compact { - for i, frag := range frags { - if i > 0 { - if err := w.w.WriteByte(' '); err != nil { - return n, err - } - n++ - } - nn, err := w.w.Write(frag) - n += nn - if err != nil { - return n, err - } - } - return n, nil - } - - for i, frag := range frags { - if w.complete { - w.writeIndent() - } - nn, err := w.w.Write(frag) - n += nn - if err != nil { - return n, err - } - if i+1 < len(frags) { - if err := w.w.WriteByte('\n'); err != nil { - return n, err - } - n++ - } - } - w.complete = len(frags[len(frags)-1]) == 0 - return n, nil -} - -func (w *textWriter) WriteByte(c byte) error { - if w.compact && c == '\n' { - c = ' ' - } - if !w.compact && w.complete { - w.writeIndent() - } - err := w.w.WriteByte(c) - w.complete = c == '\n' - return err -} - -func (w *textWriter) indent() { w.ind++ } - -func (w *textWriter) unindent() { - if w.ind == 0 { - log.Print("proto: textWriter unindented too far") - return - } - w.ind-- -} - -func writeName(w *textWriter, props *Properties) error { - if _, err := w.WriteString(props.OrigName); err != nil { - return err - } - if props.Wire != "group" { - return w.WriteByte(':') - } - return nil -} - -// raw is the interface satisfied by RawMessage. -type raw interface { - Bytes() []byte -} - -func requiresQuotes(u string) bool { - // When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted. - for _, ch := range u { - switch { - case ch == '.' || ch == '/' || ch == '_': - continue - case '0' <= ch && ch <= '9': - continue - case 'A' <= ch && ch <= 'Z': - continue - case 'a' <= ch && ch <= 'z': - continue - default: - return true - } - } - return false -} - -// isAny reports whether sv is a google.protobuf.Any message -func isAny(sv reflect.Value) bool { - type wkt interface { - XXX_WellKnownType() string - } - t, ok := sv.Addr().Interface().(wkt) - return ok && t.XXX_WellKnownType() == "Any" -} - -// writeProto3Any writes an expanded google.protobuf.Any message. -// -// It returns (false, nil) if sv value can't be unmarshaled (e.g. because -// required messages are not linked in). -// -// It returns (true, error) when sv was written in expanded format or an error -// was encountered. -func (tm *TextMarshaler) writeProto3Any(w *textWriter, sv reflect.Value) (bool, error) { - turl := sv.FieldByName("TypeUrl") - val := sv.FieldByName("Value") - if !turl.IsValid() || !val.IsValid() { - return true, errors.New("proto: invalid google.protobuf.Any message") - } - - b, ok := val.Interface().([]byte) - if !ok { - return true, errors.New("proto: invalid google.protobuf.Any message") - } - - parts := strings.Split(turl.String(), "/") - mt := MessageType(parts[len(parts)-1]) - if mt == nil { - return false, nil - } - m := reflect.New(mt.Elem()) - if err := Unmarshal(b, m.Interface().(Message)); err != nil { - return false, nil - } - w.Write([]byte("[")) - u := turl.String() - if requiresQuotes(u) { - writeString(w, u) - } else { - w.Write([]byte(u)) - } - if w.compact { - w.Write([]byte("]:<")) - } else { - w.Write([]byte("]: <\n")) - w.ind++ - } - if err := tm.writeStruct(w, m.Elem()); err != nil { - return true, err - } - if w.compact { - w.Write([]byte("> ")) - } else { - w.ind-- - w.Write([]byte(">\n")) - } - return true, nil -} - -func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { - if tm.ExpandAny && isAny(sv) { - if canExpand, err := tm.writeProto3Any(w, sv); canExpand { - return err - } - } - st := sv.Type() - sprops := GetProperties(st) - for i := 0; i < sv.NumField(); i++ { - fv := sv.Field(i) - props := sprops.Prop[i] - name := st.Field(i).Name - - if strings.HasPrefix(name, "XXX_") { - // There are two XXX_ fields: - // XXX_unrecognized []byte - // XXX_extensions map[int32]proto.Extension - // The first is handled here; - // the second is handled at the bottom of this function. - if name == "XXX_unrecognized" && !fv.IsNil() { - if err := writeUnknownStruct(w, fv.Interface().([]byte)); err != nil { - return err - } - } - continue - } - if fv.Kind() == reflect.Ptr && fv.IsNil() { - // Field not filled in. This could be an optional field or - // a required field that wasn't filled in. Either way, there - // isn't anything we can show for it. - continue - } - if fv.Kind() == reflect.Slice && fv.IsNil() { - // Repeated field that is empty, or a bytes field that is unused. - continue - } - - if props.Repeated && fv.Kind() == reflect.Slice { - // Repeated field. - for j := 0; j < fv.Len(); j++ { - if err := writeName(w, props); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte(' '); err != nil { - return err - } - } - v := fv.Index(j) - if v.Kind() == reflect.Ptr && v.IsNil() { - // A nil message in a repeated field is not valid, - // but we can handle that more gracefully than panicking. - if _, err := w.Write([]byte("\n")); err != nil { - return err - } - continue - } - if err := tm.writeAny(w, v, props); err != nil { - return err - } - if err := w.WriteByte('\n'); err != nil { - return err - } - } - continue - } - if fv.Kind() == reflect.Map { - // Map fields are rendered as a repeated struct with key/value fields. - keys := fv.MapKeys() - sort.Sort(mapKeys(keys)) - for _, key := range keys { - val := fv.MapIndex(key) - if err := writeName(w, props); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte(' '); err != nil { - return err - } - } - // open struct - if err := w.WriteByte('<'); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte('\n'); err != nil { - return err - } - } - w.indent() - // key - if _, err := w.WriteString("key:"); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte(' '); err != nil { - return err - } - } - if err := tm.writeAny(w, key, props.mkeyprop); err != nil { - return err - } - if err := w.WriteByte('\n'); err != nil { - return err - } - // nil values aren't legal, but we can avoid panicking because of them. - if val.Kind() != reflect.Ptr || !val.IsNil() { - // value - if _, err := w.WriteString("value:"); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte(' '); err != nil { - return err - } - } - if err := tm.writeAny(w, val, props.mvalprop); err != nil { - return err - } - if err := w.WriteByte('\n'); err != nil { - return err - } - } - // close struct - w.unindent() - if err := w.WriteByte('>'); err != nil { - return err - } - if err := w.WriteByte('\n'); err != nil { - return err - } - } - continue - } - if props.proto3 && fv.Kind() == reflect.Slice && fv.Len() == 0 { - // empty bytes field - continue - } - if fv.Kind() != reflect.Ptr && fv.Kind() != reflect.Slice { - // proto3 non-repeated scalar field; skip if zero value - if isProto3Zero(fv) { - continue - } - } - - if fv.Kind() == reflect.Interface { - // Check if it is a oneof. - if st.Field(i).Tag.Get("protobuf_oneof") != "" { - // fv is nil, or holds a pointer to generated struct. - // That generated struct has exactly one field, - // which has a protobuf struct tag. - if fv.IsNil() { - continue - } - inner := fv.Elem().Elem() // interface -> *T -> T - tag := inner.Type().Field(0).Tag.Get("protobuf") - props = new(Properties) // Overwrite the outer props var, but not its pointee. - props.Parse(tag) - // Write the value in the oneof, not the oneof itself. - fv = inner.Field(0) - - // Special case to cope with malformed messages gracefully: - // If the value in the oneof is a nil pointer, don't panic - // in writeAny. - if fv.Kind() == reflect.Ptr && fv.IsNil() { - // Use errors.New so writeAny won't render quotes. - msg := errors.New("/* nil */") - fv = reflect.ValueOf(&msg).Elem() - } - } - } - - if err := writeName(w, props); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte(' '); err != nil { - return err - } - } - if b, ok := fv.Interface().(raw); ok { - if err := writeRaw(w, b.Bytes()); err != nil { - return err - } - continue - } - - // Enums have a String method, so writeAny will work fine. - if err := tm.writeAny(w, fv, props); err != nil { - return err - } - - if err := w.WriteByte('\n'); err != nil { - return err - } - } - - // Extensions (the XXX_extensions field). - pv := sv.Addr() - if _, ok := extendable(pv.Interface()); ok { - if err := tm.writeExtensions(w, pv); err != nil { - return err - } - } - - return nil -} - -// writeRaw writes an uninterpreted raw message. -func writeRaw(w *textWriter, b []byte) error { - if err := w.WriteByte('<'); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte('\n'); err != nil { - return err - } - } - w.indent() - if err := writeUnknownStruct(w, b); err != nil { - return err - } - w.unindent() - if err := w.WriteByte('>'); err != nil { - return err - } - return nil -} - -// writeAny writes an arbitrary field. -func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error { - v = reflect.Indirect(v) - - // Floats have special cases. - if v.Kind() == reflect.Float32 || v.Kind() == reflect.Float64 { - x := v.Float() - var b []byte - switch { - case math.IsInf(x, 1): - b = posInf - case math.IsInf(x, -1): - b = negInf - case math.IsNaN(x): - b = nan - } - if b != nil { - _, err := w.Write(b) - return err - } - // Other values are handled below. - } - - // We don't attempt to serialise every possible value type; only those - // that can occur in protocol buffers. - switch v.Kind() { - case reflect.Slice: - // Should only be a []byte; repeated fields are handled in writeStruct. - if err := writeString(w, string(v.Bytes())); err != nil { - return err - } - case reflect.String: - if err := writeString(w, v.String()); err != nil { - return err - } - case reflect.Struct: - // Required/optional group/message. - var bra, ket byte = '<', '>' - if props != nil && props.Wire == "group" { - bra, ket = '{', '}' - } - if err := w.WriteByte(bra); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte('\n'); err != nil { - return err - } - } - w.indent() - if etm, ok := v.Interface().(encoding.TextMarshaler); ok { - text, err := etm.MarshalText() - if err != nil { - return err - } - if _, err = w.Write(text); err != nil { - return err - } - } else if err := tm.writeStruct(w, v); err != nil { - return err - } - w.unindent() - if err := w.WriteByte(ket); err != nil { - return err - } - default: - _, err := fmt.Fprint(w, v.Interface()) - return err - } - return nil -} - -// equivalent to C's isprint. -func isprint(c byte) bool { - return c >= 0x20 && c < 0x7f -} - -// writeString writes a string in the protocol buffer text format. -// It is similar to strconv.Quote except we don't use Go escape sequences, -// we treat the string as a byte sequence, and we use octal escapes. -// These differences are to maintain interoperability with the other -// languages' implementations of the text format. -func writeString(w *textWriter, s string) error { - // use WriteByte here to get any needed indent - if err := w.WriteByte('"'); err != nil { - return err - } - // Loop over the bytes, not the runes. - for i := 0; i < len(s); i++ { - var err error - // Divergence from C++: we don't escape apostrophes. - // There's no need to escape them, and the C++ parser - // copes with a naked apostrophe. - switch c := s[i]; c { - case '\n': - _, err = w.w.Write(backslashN) - case '\r': - _, err = w.w.Write(backslashR) - case '\t': - _, err = w.w.Write(backslashT) - case '"': - _, err = w.w.Write(backslashDQ) - case '\\': - _, err = w.w.Write(backslashBS) - default: - if isprint(c) { - err = w.w.WriteByte(c) - } else { - _, err = fmt.Fprintf(w.w, "\\%03o", c) - } - } - if err != nil { - return err - } - } - return w.WriteByte('"') -} - -func writeUnknownStruct(w *textWriter, data []byte) (err error) { - if !w.compact { - if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil { - return err - } - } - b := NewBuffer(data) - for b.index < len(b.buf) { - x, err := b.DecodeVarint() - if err != nil { - _, err := fmt.Fprintf(w, "/* %v */\n", err) - return err - } - wire, tag := x&7, x>>3 - if wire == WireEndGroup { - w.unindent() - if _, err := w.Write(endBraceNewline); err != nil { - return err - } - continue - } - if _, err := fmt.Fprint(w, tag); err != nil { - return err - } - if wire != WireStartGroup { - if err := w.WriteByte(':'); err != nil { - return err - } - } - if !w.compact || wire == WireStartGroup { - if err := w.WriteByte(' '); err != nil { - return err - } - } - switch wire { - case WireBytes: - buf, e := b.DecodeRawBytes(false) - if e == nil { - _, err = fmt.Fprintf(w, "%q", buf) - } else { - _, err = fmt.Fprintf(w, "/* %v */", e) - } - case WireFixed32: - x, err = b.DecodeFixed32() - err = writeUnknownInt(w, x, err) - case WireFixed64: - x, err = b.DecodeFixed64() - err = writeUnknownInt(w, x, err) - case WireStartGroup: - err = w.WriteByte('{') - w.indent() - case WireVarint: - x, err = b.DecodeVarint() - err = writeUnknownInt(w, x, err) - default: - _, err = fmt.Fprintf(w, "/* unknown wire type %d */", wire) - } - if err != nil { - return err - } - if err = w.WriteByte('\n'); err != nil { - return err - } - } - return nil -} - -func writeUnknownInt(w *textWriter, x uint64, err error) error { - if err == nil { - _, err = fmt.Fprint(w, x) - } else { - _, err = fmt.Fprintf(w, "/* %v */", err) - } - return err -} - -type int32Slice []int32 - -func (s int32Slice) Len() int { return len(s) } -func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] } -func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - -// writeExtensions writes all the extensions in pv. -// pv is assumed to be a pointer to a protocol message struct that is extendable. -func (tm *TextMarshaler) writeExtensions(w *textWriter, pv reflect.Value) error { - emap := extensionMaps[pv.Type().Elem()] - ep, _ := extendable(pv.Interface()) - - // Order the extensions by ID. - // This isn't strictly necessary, but it will give us - // canonical output, which will also make testing easier. - m, mu := ep.extensionsRead() - if m == nil { - return nil - } - mu.Lock() - ids := make([]int32, 0, len(m)) - for id := range m { - ids = append(ids, id) - } - sort.Sort(int32Slice(ids)) - mu.Unlock() - - for _, extNum := range ids { - ext := m[extNum] - var desc *ExtensionDesc - if emap != nil { - desc = emap[extNum] - } - if desc == nil { - // Unknown extension. - if err := writeUnknownStruct(w, ext.enc); err != nil { - return err - } - continue - } - - pb, err := GetExtension(ep, desc) - if err != nil { - return fmt.Errorf("failed getting extension: %v", err) - } - - // Repeated extensions will appear as a slice. - if !desc.repeated() { - if err := tm.writeExtension(w, desc.Name, pb); err != nil { - return err - } - } else { - v := reflect.ValueOf(pb) - for i := 0; i < v.Len(); i++ { - if err := tm.writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil { - return err - } - } - } - } - return nil -} - -func (tm *TextMarshaler) writeExtension(w *textWriter, name string, pb interface{}) error { - if _, err := fmt.Fprintf(w, "[%s]:", name); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte(' '); err != nil { - return err - } - } - if err := tm.writeAny(w, reflect.ValueOf(pb), nil); err != nil { - return err - } - if err := w.WriteByte('\n'); err != nil { - return err - } - return nil -} - -func (w *textWriter) writeIndent() { - if !w.complete { - return - } - remain := w.ind * 2 - for remain > 0 { - n := remain - if n > len(spaces) { - n = len(spaces) - } - w.w.Write(spaces[:n]) - remain -= n - } - w.complete = false -} - -// TextMarshaler is a configurable text format marshaler. -type TextMarshaler struct { - Compact bool // use compact text format (one line). - ExpandAny bool // expand google.protobuf.Any messages of known types -} - -// Marshal writes a given protocol buffer in text format. -// The only errors returned are from w. -func (tm *TextMarshaler) Marshal(w io.Writer, pb Message) error { - val := reflect.ValueOf(pb) - if pb == nil || val.IsNil() { - w.Write([]byte("")) - return nil - } - var bw *bufio.Writer - ww, ok := w.(writer) - if !ok { - bw = bufio.NewWriter(w) - ww = bw - } - aw := &textWriter{ - w: ww, - complete: true, - compact: tm.Compact, - } - - if etm, ok := pb.(encoding.TextMarshaler); ok { - text, err := etm.MarshalText() - if err != nil { - return err - } - if _, err = aw.Write(text); err != nil { - return err - } - if bw != nil { - return bw.Flush() - } - return nil - } - // Dereference the received pointer so we don't have outer < and >. - v := reflect.Indirect(val) - if err := tm.writeStruct(aw, v); err != nil { - return err - } - if bw != nil { - return bw.Flush() - } - return nil -} - -// Text is the same as Marshal, but returns the string directly. -func (tm *TextMarshaler) Text(pb Message) string { - var buf bytes.Buffer - tm.Marshal(&buf, pb) - return buf.String() -} - -var ( - defaultTextMarshaler = TextMarshaler{} - compactTextMarshaler = TextMarshaler{Compact: true} -) - -// TODO: consider removing some of the Marshal functions below. - -// MarshalText writes a given protocol buffer in text format. -// The only errors returned are from w. -func MarshalText(w io.Writer, pb Message) error { return defaultTextMarshaler.Marshal(w, pb) } - -// MarshalTextString is the same as MarshalText, but returns the string directly. -func MarshalTextString(pb Message) string { return defaultTextMarshaler.Text(pb) } - -// CompactText writes a given protocol buffer in compact text format (one line). -func CompactText(w io.Writer, pb Message) error { return compactTextMarshaler.Marshal(w, pb) } - -// CompactTextString is the same as CompactText, but returns the string directly. -func CompactTextString(pb Message) string { return compactTextMarshaler.Text(pb) } diff --git a/vendor/github.com/golang/protobuf/proto/text_parser.go b/vendor/github.com/golang/protobuf/proto/text_parser.go deleted file mode 100644 index 5e14513..0000000 --- a/vendor/github.com/golang/protobuf/proto/text_parser.go +++ /dev/null @@ -1,895 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -// Functions for parsing the Text protocol buffer format. -// TODO: message sets. - -import ( - "encoding" - "errors" - "fmt" - "reflect" - "strconv" - "strings" - "unicode/utf8" -) - -// Error string emitted when deserializing Any and fields are already set -const anyRepeatedlyUnpacked = "Any message unpacked multiple times, or %q already set" - -type ParseError struct { - Message string - Line int // 1-based line number - Offset int // 0-based byte offset from start of input -} - -func (p *ParseError) Error() string { - if p.Line == 1 { - // show offset only for first line - return fmt.Sprintf("line 1.%d: %v", p.Offset, p.Message) - } - return fmt.Sprintf("line %d: %v", p.Line, p.Message) -} - -type token struct { - value string - err *ParseError - line int // line number - offset int // byte number from start of input, not start of line - unquoted string // the unquoted version of value, if it was a quoted string -} - -func (t *token) String() string { - if t.err == nil { - return fmt.Sprintf("%q (line=%d, offset=%d)", t.value, t.line, t.offset) - } - return fmt.Sprintf("parse error: %v", t.err) -} - -type textParser struct { - s string // remaining input - done bool // whether the parsing is finished (success or error) - backed bool // whether back() was called - offset, line int - cur token -} - -func newTextParser(s string) *textParser { - p := new(textParser) - p.s = s - p.line = 1 - p.cur.line = 1 - return p -} - -func (p *textParser) errorf(format string, a ...interface{}) *ParseError { - pe := &ParseError{fmt.Sprintf(format, a...), p.cur.line, p.cur.offset} - p.cur.err = pe - p.done = true - return pe -} - -// Numbers and identifiers are matched by [-+._A-Za-z0-9] -func isIdentOrNumberChar(c byte) bool { - switch { - case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z': - return true - case '0' <= c && c <= '9': - return true - } - switch c { - case '-', '+', '.', '_': - return true - } - return false -} - -func isWhitespace(c byte) bool { - switch c { - case ' ', '\t', '\n', '\r': - return true - } - return false -} - -func isQuote(c byte) bool { - switch c { - case '"', '\'': - return true - } - return false -} - -func (p *textParser) skipWhitespace() { - i := 0 - for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') { - if p.s[i] == '#' { - // comment; skip to end of line or input - for i < len(p.s) && p.s[i] != '\n' { - i++ - } - if i == len(p.s) { - break - } - } - if p.s[i] == '\n' { - p.line++ - } - i++ - } - p.offset += i - p.s = p.s[i:len(p.s)] - if len(p.s) == 0 { - p.done = true - } -} - -func (p *textParser) advance() { - // Skip whitespace - p.skipWhitespace() - if p.done { - return - } - - // Start of non-whitespace - p.cur.err = nil - p.cur.offset, p.cur.line = p.offset, p.line - p.cur.unquoted = "" - switch p.s[0] { - case '<', '>', '{', '}', ':', '[', ']', ';', ',', '/': - // Single symbol - p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)] - case '"', '\'': - // Quoted string - i := 1 - for i < len(p.s) && p.s[i] != p.s[0] && p.s[i] != '\n' { - if p.s[i] == '\\' && i+1 < len(p.s) { - // skip escaped char - i++ - } - i++ - } - if i >= len(p.s) || p.s[i] != p.s[0] { - p.errorf("unmatched quote") - return - } - unq, err := unquoteC(p.s[1:i], rune(p.s[0])) - if err != nil { - p.errorf("invalid quoted string %s: %v", p.s[0:i+1], err) - return - } - p.cur.value, p.s = p.s[0:i+1], p.s[i+1:len(p.s)] - p.cur.unquoted = unq - default: - i := 0 - for i < len(p.s) && isIdentOrNumberChar(p.s[i]) { - i++ - } - if i == 0 { - p.errorf("unexpected byte %#x", p.s[0]) - return - } - p.cur.value, p.s = p.s[0:i], p.s[i:len(p.s)] - } - p.offset += len(p.cur.value) -} - -var ( - errBadUTF8 = errors.New("proto: bad UTF-8") - errBadHex = errors.New("proto: bad hexadecimal") -) - -func unquoteC(s string, quote rune) (string, error) { - // This is based on C++'s tokenizer.cc. - // Despite its name, this is *not* parsing C syntax. - // For instance, "\0" is an invalid quoted string. - - // Avoid allocation in trivial cases. - simple := true - for _, r := range s { - if r == '\\' || r == quote { - simple = false - break - } - } - if simple { - return s, nil - } - - buf := make([]byte, 0, 3*len(s)/2) - for len(s) > 0 { - r, n := utf8.DecodeRuneInString(s) - if r == utf8.RuneError && n == 1 { - return "", errBadUTF8 - } - s = s[n:] - if r != '\\' { - if r < utf8.RuneSelf { - buf = append(buf, byte(r)) - } else { - buf = append(buf, string(r)...) - } - continue - } - - ch, tail, err := unescape(s) - if err != nil { - return "", err - } - buf = append(buf, ch...) - s = tail - } - return string(buf), nil -} - -func unescape(s string) (ch string, tail string, err error) { - r, n := utf8.DecodeRuneInString(s) - if r == utf8.RuneError && n == 1 { - return "", "", errBadUTF8 - } - s = s[n:] - switch r { - case 'a': - return "\a", s, nil - case 'b': - return "\b", s, nil - case 'f': - return "\f", s, nil - case 'n': - return "\n", s, nil - case 'r': - return "\r", s, nil - case 't': - return "\t", s, nil - case 'v': - return "\v", s, nil - case '?': - return "?", s, nil // trigraph workaround - case '\'', '"', '\\': - return string(r), s, nil - case '0', '1', '2', '3', '4', '5', '6', '7', 'x', 'X': - if len(s) < 2 { - return "", "", fmt.Errorf(`\%c requires 2 following digits`, r) - } - base := 8 - ss := s[:2] - s = s[2:] - if r == 'x' || r == 'X' { - base = 16 - } else { - ss = string(r) + ss - } - i, err := strconv.ParseUint(ss, base, 8) - if err != nil { - return "", "", err - } - return string([]byte{byte(i)}), s, nil - case 'u', 'U': - n := 4 - if r == 'U' { - n = 8 - } - if len(s) < n { - return "", "", fmt.Errorf(`\%c requires %d digits`, r, n) - } - - bs := make([]byte, n/2) - for i := 0; i < n; i += 2 { - a, ok1 := unhex(s[i]) - b, ok2 := unhex(s[i+1]) - if !ok1 || !ok2 { - return "", "", errBadHex - } - bs[i/2] = a<<4 | b - } - s = s[n:] - return string(bs), s, nil - } - return "", "", fmt.Errorf(`unknown escape \%c`, r) -} - -// Adapted from src/pkg/strconv/quote.go. -func unhex(b byte) (v byte, ok bool) { - switch { - case '0' <= b && b <= '9': - return b - '0', true - case 'a' <= b && b <= 'f': - return b - 'a' + 10, true - case 'A' <= b && b <= 'F': - return b - 'A' + 10, true - } - return 0, false -} - -// Back off the parser by one token. Can only be done between calls to next(). -// It makes the next advance() a no-op. -func (p *textParser) back() { p.backed = true } - -// Advances the parser and returns the new current token. -func (p *textParser) next() *token { - if p.backed || p.done { - p.backed = false - return &p.cur - } - p.advance() - if p.done { - p.cur.value = "" - } else if len(p.cur.value) > 0 && isQuote(p.cur.value[0]) { - // Look for multiple quoted strings separated by whitespace, - // and concatenate them. - cat := p.cur - for { - p.skipWhitespace() - if p.done || !isQuote(p.s[0]) { - break - } - p.advance() - if p.cur.err != nil { - return &p.cur - } - cat.value += " " + p.cur.value - cat.unquoted += p.cur.unquoted - } - p.done = false // parser may have seen EOF, but we want to return cat - p.cur = cat - } - return &p.cur -} - -func (p *textParser) consumeToken(s string) error { - tok := p.next() - if tok.err != nil { - return tok.err - } - if tok.value != s { - p.back() - return p.errorf("expected %q, found %q", s, tok.value) - } - return nil -} - -// Return a RequiredNotSetError indicating which required field was not set. -func (p *textParser) missingRequiredFieldError(sv reflect.Value) *RequiredNotSetError { - st := sv.Type() - sprops := GetProperties(st) - for i := 0; i < st.NumField(); i++ { - if !isNil(sv.Field(i)) { - continue - } - - props := sprops.Prop[i] - if props.Required { - return &RequiredNotSetError{fmt.Sprintf("%v.%v", st, props.OrigName)} - } - } - return &RequiredNotSetError{fmt.Sprintf("%v.", st)} // should not happen -} - -// Returns the index in the struct for the named field, as well as the parsed tag properties. -func structFieldByName(sprops *StructProperties, name string) (int, *Properties, bool) { - i, ok := sprops.decoderOrigNames[name] - if ok { - return i, sprops.Prop[i], true - } - return -1, nil, false -} - -// Consume a ':' from the input stream (if the next token is a colon), -// returning an error if a colon is needed but not present. -func (p *textParser) checkForColon(props *Properties, typ reflect.Type) *ParseError { - tok := p.next() - if tok.err != nil { - return tok.err - } - if tok.value != ":" { - // Colon is optional when the field is a group or message. - needColon := true - switch props.Wire { - case "group": - needColon = false - case "bytes": - // A "bytes" field is either a message, a string, or a repeated field; - // those three become *T, *string and []T respectively, so we can check for - // this field being a pointer to a non-string. - if typ.Kind() == reflect.Ptr { - // *T or *string - if typ.Elem().Kind() == reflect.String { - break - } - } else if typ.Kind() == reflect.Slice { - // []T or []*T - if typ.Elem().Kind() != reflect.Ptr { - break - } - } else if typ.Kind() == reflect.String { - // The proto3 exception is for a string field, - // which requires a colon. - break - } - needColon = false - } - if needColon { - return p.errorf("expected ':', found %q", tok.value) - } - p.back() - } - return nil -} - -func (p *textParser) readStruct(sv reflect.Value, terminator string) error { - st := sv.Type() - sprops := GetProperties(st) - reqCount := sprops.reqCount - var reqFieldErr error - fieldSet := make(map[string]bool) - // A struct is a sequence of "name: value", terminated by one of - // '>' or '}', or the end of the input. A name may also be - // "[extension]" or "[type/url]". - // - // The whole struct can also be an expanded Any message, like: - // [type/url] < ... struct contents ... > - for { - tok := p.next() - if tok.err != nil { - return tok.err - } - if tok.value == terminator { - break - } - if tok.value == "[" { - // Looks like an extension or an Any. - // - // TODO: Check whether we need to handle - // namespace rooted names (e.g. ".something.Foo"). - extName, err := p.consumeExtName() - if err != nil { - return err - } - - if s := strings.LastIndex(extName, "/"); s >= 0 { - // If it contains a slash, it's an Any type URL. - messageName := extName[s+1:] - mt := MessageType(messageName) - if mt == nil { - return p.errorf("unrecognized message %q in google.protobuf.Any", messageName) - } - tok = p.next() - if tok.err != nil { - return tok.err - } - // consume an optional colon - if tok.value == ":" { - tok = p.next() - if tok.err != nil { - return tok.err - } - } - var terminator string - switch tok.value { - case "<": - terminator = ">" - case "{": - terminator = "}" - default: - return p.errorf("expected '{' or '<', found %q", tok.value) - } - v := reflect.New(mt.Elem()) - if pe := p.readStruct(v.Elem(), terminator); pe != nil { - return pe - } - b, err := Marshal(v.Interface().(Message)) - if err != nil { - return p.errorf("failed to marshal message of type %q: %v", messageName, err) - } - if fieldSet["type_url"] { - return p.errorf(anyRepeatedlyUnpacked, "type_url") - } - if fieldSet["value"] { - return p.errorf(anyRepeatedlyUnpacked, "value") - } - sv.FieldByName("TypeUrl").SetString(extName) - sv.FieldByName("Value").SetBytes(b) - fieldSet["type_url"] = true - fieldSet["value"] = true - continue - } - - var desc *ExtensionDesc - // This could be faster, but it's functional. - // TODO: Do something smarter than a linear scan. - for _, d := range RegisteredExtensions(reflect.New(st).Interface().(Message)) { - if d.Name == extName { - desc = d - break - } - } - if desc == nil { - return p.errorf("unrecognized extension %q", extName) - } - - props := &Properties{} - props.Parse(desc.Tag) - - typ := reflect.TypeOf(desc.ExtensionType) - if err := p.checkForColon(props, typ); err != nil { - return err - } - - rep := desc.repeated() - - // Read the extension structure, and set it in - // the value we're constructing. - var ext reflect.Value - if !rep { - ext = reflect.New(typ).Elem() - } else { - ext = reflect.New(typ.Elem()).Elem() - } - if err := p.readAny(ext, props); err != nil { - if _, ok := err.(*RequiredNotSetError); !ok { - return err - } - reqFieldErr = err - } - ep := sv.Addr().Interface().(Message) - if !rep { - SetExtension(ep, desc, ext.Interface()) - } else { - old, err := GetExtension(ep, desc) - var sl reflect.Value - if err == nil { - sl = reflect.ValueOf(old) // existing slice - } else { - sl = reflect.MakeSlice(typ, 0, 1) - } - sl = reflect.Append(sl, ext) - SetExtension(ep, desc, sl.Interface()) - } - if err := p.consumeOptionalSeparator(); err != nil { - return err - } - continue - } - - // This is a normal, non-extension field. - name := tok.value - var dst reflect.Value - fi, props, ok := structFieldByName(sprops, name) - if ok { - dst = sv.Field(fi) - } else if oop, ok := sprops.OneofTypes[name]; ok { - // It is a oneof. - props = oop.Prop - nv := reflect.New(oop.Type.Elem()) - dst = nv.Elem().Field(0) - field := sv.Field(oop.Field) - if !field.IsNil() { - return p.errorf("field '%s' would overwrite already parsed oneof '%s'", name, sv.Type().Field(oop.Field).Name) - } - field.Set(nv) - } - if !dst.IsValid() { - return p.errorf("unknown field name %q in %v", name, st) - } - - if dst.Kind() == reflect.Map { - // Consume any colon. - if err := p.checkForColon(props, dst.Type()); err != nil { - return err - } - - // Construct the map if it doesn't already exist. - if dst.IsNil() { - dst.Set(reflect.MakeMap(dst.Type())) - } - key := reflect.New(dst.Type().Key()).Elem() - val := reflect.New(dst.Type().Elem()).Elem() - - // The map entry should be this sequence of tokens: - // < key : KEY value : VALUE > - // However, implementations may omit key or value, and technically - // we should support them in any order. See b/28924776 for a time - // this went wrong. - - tok := p.next() - var terminator string - switch tok.value { - case "<": - terminator = ">" - case "{": - terminator = "}" - default: - return p.errorf("expected '{' or '<', found %q", tok.value) - } - for { - tok := p.next() - if tok.err != nil { - return tok.err - } - if tok.value == terminator { - break - } - switch tok.value { - case "key": - if err := p.consumeToken(":"); err != nil { - return err - } - if err := p.readAny(key, props.mkeyprop); err != nil { - return err - } - if err := p.consumeOptionalSeparator(); err != nil { - return err - } - case "value": - if err := p.checkForColon(props.mvalprop, dst.Type().Elem()); err != nil { - return err - } - if err := p.readAny(val, props.mvalprop); err != nil { - return err - } - if err := p.consumeOptionalSeparator(); err != nil { - return err - } - default: - p.back() - return p.errorf(`expected "key", "value", or %q, found %q`, terminator, tok.value) - } - } - - dst.SetMapIndex(key, val) - continue - } - - // Check that it's not already set if it's not a repeated field. - if !props.Repeated && fieldSet[name] { - return p.errorf("non-repeated field %q was repeated", name) - } - - if err := p.checkForColon(props, dst.Type()); err != nil { - return err - } - - // Parse into the field. - fieldSet[name] = true - if err := p.readAny(dst, props); err != nil { - if _, ok := err.(*RequiredNotSetError); !ok { - return err - } - reqFieldErr = err - } - if props.Required { - reqCount-- - } - - if err := p.consumeOptionalSeparator(); err != nil { - return err - } - - } - - if reqCount > 0 { - return p.missingRequiredFieldError(sv) - } - return reqFieldErr -} - -// consumeExtName consumes extension name or expanded Any type URL and the -// following ']'. It returns the name or URL consumed. -func (p *textParser) consumeExtName() (string, error) { - tok := p.next() - if tok.err != nil { - return "", tok.err - } - - // If extension name or type url is quoted, it's a single token. - if len(tok.value) > 2 && isQuote(tok.value[0]) && tok.value[len(tok.value)-1] == tok.value[0] { - name, err := unquoteC(tok.value[1:len(tok.value)-1], rune(tok.value[0])) - if err != nil { - return "", err - } - return name, p.consumeToken("]") - } - - // Consume everything up to "]" - var parts []string - for tok.value != "]" { - parts = append(parts, tok.value) - tok = p.next() - if tok.err != nil { - return "", p.errorf("unrecognized type_url or extension name: %s", tok.err) - } - } - return strings.Join(parts, ""), nil -} - -// consumeOptionalSeparator consumes an optional semicolon or comma. -// It is used in readStruct to provide backward compatibility. -func (p *textParser) consumeOptionalSeparator() error { - tok := p.next() - if tok.err != nil { - return tok.err - } - if tok.value != ";" && tok.value != "," { - p.back() - } - return nil -} - -func (p *textParser) readAny(v reflect.Value, props *Properties) error { - tok := p.next() - if tok.err != nil { - return tok.err - } - if tok.value == "" { - return p.errorf("unexpected EOF") - } - - switch fv := v; fv.Kind() { - case reflect.Slice: - at := v.Type() - if at.Elem().Kind() == reflect.Uint8 { - // Special case for []byte - if tok.value[0] != '"' && tok.value[0] != '\'' { - // Deliberately written out here, as the error after - // this switch statement would write "invalid []byte: ...", - // which is not as user-friendly. - return p.errorf("invalid string: %v", tok.value) - } - bytes := []byte(tok.unquoted) - fv.Set(reflect.ValueOf(bytes)) - return nil - } - // Repeated field. - if tok.value == "[" { - // Repeated field with list notation, like [1,2,3]. - for { - fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) - err := p.readAny(fv.Index(fv.Len()-1), props) - if err != nil { - return err - } - tok := p.next() - if tok.err != nil { - return tok.err - } - if tok.value == "]" { - break - } - if tok.value != "," { - return p.errorf("Expected ']' or ',' found %q", tok.value) - } - } - return nil - } - // One value of the repeated field. - p.back() - fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) - return p.readAny(fv.Index(fv.Len()-1), props) - case reflect.Bool: - // true/1/t/True or false/f/0/False. - switch tok.value { - case "true", "1", "t", "True": - fv.SetBool(true) - return nil - case "false", "0", "f", "False": - fv.SetBool(false) - return nil - } - case reflect.Float32, reflect.Float64: - v := tok.value - // Ignore 'f' for compatibility with output generated by C++, but don't - // remove 'f' when the value is "-inf" or "inf". - if strings.HasSuffix(v, "f") && tok.value != "-inf" && tok.value != "inf" { - v = v[:len(v)-1] - } - if f, err := strconv.ParseFloat(v, fv.Type().Bits()); err == nil { - fv.SetFloat(f) - return nil - } - case reflect.Int32: - if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil { - fv.SetInt(x) - return nil - } - - if len(props.Enum) == 0 { - break - } - m, ok := enumValueMaps[props.Enum] - if !ok { - break - } - x, ok := m[tok.value] - if !ok { - break - } - fv.SetInt(int64(x)) - return nil - case reflect.Int64: - if x, err := strconv.ParseInt(tok.value, 0, 64); err == nil { - fv.SetInt(x) - return nil - } - - case reflect.Ptr: - // A basic field (indirected through pointer), or a repeated message/group - p.back() - fv.Set(reflect.New(fv.Type().Elem())) - return p.readAny(fv.Elem(), props) - case reflect.String: - if tok.value[0] == '"' || tok.value[0] == '\'' { - fv.SetString(tok.unquoted) - return nil - } - case reflect.Struct: - var terminator string - switch tok.value { - case "{": - terminator = "}" - case "<": - terminator = ">" - default: - return p.errorf("expected '{' or '<', found %q", tok.value) - } - // TODO: Handle nested messages which implement encoding.TextUnmarshaler. - return p.readStruct(fv, terminator) - case reflect.Uint32: - if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil { - fv.SetUint(x) - return nil - } - case reflect.Uint64: - if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil { - fv.SetUint(x) - return nil - } - } - return p.errorf("invalid %v: %v", v.Type(), tok.value) -} - -// UnmarshalText reads a protocol buffer in Text format. UnmarshalText resets pb -// before starting to unmarshal, so any existing data in pb is always removed. -// If a required field is not set and no other error occurs, -// UnmarshalText returns *RequiredNotSetError. -func UnmarshalText(s string, pb Message) error { - if um, ok := pb.(encoding.TextUnmarshaler); ok { - err := um.UnmarshalText([]byte(s)) - return err - } - pb.Reset() - v := reflect.ValueOf(pb) - if pe := newTextParser(s).readStruct(v.Elem(), ""); pe != nil { - return pe - } - return nil -} diff --git a/vendor/github.com/matttproud/golang_protobuf_extensions/LICENSE b/vendor/github.com/matttproud/golang_protobuf_extensions/LICENSE deleted file mode 100644 index 8dada3e..0000000 --- a/vendor/github.com/matttproud/golang_protobuf_extensions/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - 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. diff --git a/vendor/github.com/matttproud/golang_protobuf_extensions/NOTICE b/vendor/github.com/matttproud/golang_protobuf_extensions/NOTICE deleted file mode 100644 index 5d8cb5b..0000000 --- a/vendor/github.com/matttproud/golang_protobuf_extensions/NOTICE +++ /dev/null @@ -1 +0,0 @@ -Copyright 2012 Matt T. Proud (matt.proud@gmail.com) diff --git a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/decode.go b/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/decode.go deleted file mode 100644 index 258c063..0000000 --- a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/decode.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2013 Matt T. Proud -// -// 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. - -package pbutil - -import ( - "encoding/binary" - "errors" - "io" - - "github.com/golang/protobuf/proto" -) - -var errInvalidVarint = errors.New("invalid varint32 encountered") - -// ReadDelimited decodes a message from the provided length-delimited stream, -// where the length is encoded as 32-bit varint prefix to the message body. -// It returns the total number of bytes read and any applicable error. This is -// roughly equivalent to the companion Java API's -// MessageLite#parseDelimitedFrom. As per the reader contract, this function -// calls r.Read repeatedly as required until exactly one message including its -// prefix is read and decoded (or an error has occurred). The function never -// reads more bytes from the stream than required. The function never returns -// an error if a message has been read and decoded correctly, even if the end -// of the stream has been reached in doing so. In that case, any subsequent -// calls return (0, io.EOF). -func ReadDelimited(r io.Reader, m proto.Message) (n int, err error) { - // Per AbstractParser#parsePartialDelimitedFrom with - // CodedInputStream#readRawVarint32. - var headerBuf [binary.MaxVarintLen32]byte - var bytesRead, varIntBytes int - var messageLength uint64 - for varIntBytes == 0 { // i.e. no varint has been decoded yet. - if bytesRead >= len(headerBuf) { - return bytesRead, errInvalidVarint - } - // We have to read byte by byte here to avoid reading more bytes - // than required. Each read byte is appended to what we have - // read before. - newBytesRead, err := r.Read(headerBuf[bytesRead : bytesRead+1]) - if newBytesRead == 0 { - if err != nil { - return bytesRead, err - } - // A Reader should not return (0, nil), but if it does, - // it should be treated as no-op (according to the - // Reader contract). So let's go on... - continue - } - bytesRead += newBytesRead - // Now present everything read so far to the varint decoder and - // see if a varint can be decoded already. - messageLength, varIntBytes = proto.DecodeVarint(headerBuf[:bytesRead]) - } - - messageBuf := make([]byte, messageLength) - newBytesRead, err := io.ReadFull(r, messageBuf) - bytesRead += newBytesRead - if err != nil { - return bytesRead, err - } - - return bytesRead, proto.Unmarshal(messageBuf, m) -} diff --git a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/doc.go b/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/doc.go deleted file mode 100644 index c318385..0000000 --- a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/doc.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2013 Matt T. Proud -// -// 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. - -// Package pbutil provides record length-delimited Protocol Buffer streaming. -package pbutil diff --git a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/encode.go b/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/encode.go deleted file mode 100644 index 8fb59ad..0000000 --- a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/encode.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2013 Matt T. Proud -// -// 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. - -package pbutil - -import ( - "encoding/binary" - "io" - - "github.com/golang/protobuf/proto" -) - -// WriteDelimited encodes and dumps a message to the provided writer prefixed -// with a 32-bit varint indicating the length of the encoded message, producing -// a length-delimited record stream, which can be used to chain together -// encoded messages of the same type together in a file. It returns the total -// number of bytes written and any applicable error. This is roughly -// equivalent to the companion Java API's MessageLite#writeDelimitedTo. -func WriteDelimited(w io.Writer, m proto.Message) (n int, err error) { - buffer, err := proto.Marshal(m) - if err != nil { - return 0, err - } - - var buf [binary.MaxVarintLen32]byte - encodedLength := binary.PutUvarint(buf[:], uint64(len(buffer))) - - sync, err := w.Write(buf[:encodedLength]) - if err != nil { - return sync, err - } - - n, err = w.Write(buffer) - return n + sync, err -} diff --git a/vendor/github.com/mindprince/gonvml/LICENSE b/vendor/github.com/mindprince/gonvml/LICENSE deleted file mode 100644 index d645695..0000000 --- a/vendor/github.com/mindprince/gonvml/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. diff --git a/vendor/github.com/mindprince/gonvml/Makefile b/vendor/github.com/mindprince/gonvml/Makefile deleted file mode 100644 index b329e96..0000000 --- a/vendor/github.com/mindprince/gonvml/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright 2017 Google Inc. -# -# 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. - -PKG=github.com/mindprince/gonvml - -.PHONY: build -build: - docker run -v $(shell pwd):/go/src/$(PKG) --workdir=/go/src/$(PKG) golang:1.8 go build cmd/example/example.go - diff --git a/vendor/github.com/mindprince/gonvml/NVML_NOTICE b/vendor/github.com/mindprince/gonvml/NVML_NOTICE deleted file mode 100644 index 3fc1313..0000000 --- a/vendor/github.com/mindprince/gonvml/NVML_NOTICE +++ /dev/null @@ -1,32 +0,0 @@ -Copyright 1993-2016 NVIDIA Corporation. All rights reserved. - -NOTICE TO USER: - -This source code is subject to NVIDIA ownership rights under U.S. and -international Copyright laws. Users and possessors of this source code -are hereby granted a nonexclusive, royalty-free license to use this code -in individual and commercial software. - -NVIDIA MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE -CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR -IMPLIED WARRANTY OF ANY KIND. NVIDIA DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. -IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL, -OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS -OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE -OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE -OR PERFORMANCE OF THIS SOURCE CODE. - -U.S. Government End Users. This source code is a "commercial item" as -that term is defined at 48 C.F.R. 2.101 (OCT 1995), consisting of -"commercial computer software" and "commercial computer software -documentation" as such terms are used in 48 C.F.R. 12.212 (SEPT 1995) -and is provided to the U.S. Government only as a commercial end item. -Consistent with 48 C.F.R.12.212 and 48 C.F.R. 227.7202-1 through -227.7202-4 (JUNE 1995), all U.S. Government End Users acquire the -source code with only those rights set forth herein. - -Any use of this source code in individual and commercial software must -include, in the user documentation and internal comments to the code, -the above Disclaimer and U.S. Government End Users Notice. diff --git a/vendor/github.com/mindprince/gonvml/README.md b/vendor/github.com/mindprince/gonvml/README.md deleted file mode 100644 index 91bbf57..0000000 --- a/vendor/github.com/mindprince/gonvml/README.md +++ /dev/null @@ -1,19 +0,0 @@ -Go Bindings for NVML --------------------- - -[NVML or NVIDIA Management -Library](https://developer.nvidia.com/nvidia-management-library-nvml) is a -C-based API that can be used for monitoring NVIDIA GPU devices. It's closed -source but can be downloaded as part of the [GPU Deployment -Kit](https://developer.nvidia.com/gpu-deployment-kit). - -The [NVML API -Reference](http://docs.nvidia.com/deploy/nvml-api/nvml-api-reference.html) -describe various methods that are available as part of NVML. - -The `nvml.h` file is included in this repository so that we don't depend on -the presence of NVML in the build environment. - -The `bindings.go` file is the cgo bridge which calls the NVML functions. The -cgo preamble in `bindings.go` uses `dlopen` to dynamically load NVML and makes -its functions available. diff --git a/vendor/github.com/mindprince/gonvml/bindings.go b/vendor/github.com/mindprince/gonvml/bindings.go deleted file mode 100644 index e204c26..0000000 --- a/vendor/github.com/mindprince/gonvml/bindings.go +++ /dev/null @@ -1,476 +0,0 @@ -/* -Copyright 2017 Google Inc. - -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. -*/ - -package gonvml - -// #cgo LDFLAGS: -ldl -/* -#include -#include -#include - -#include "nvml.h" - -// nvmlHandle is the handle for dynamically loaded libnvidia-ml.so -void *nvmlHandle; - -nvmlReturn_t (*nvmlInitFunc)(void); - -nvmlReturn_t (*nvmlShutdownFunc)(void); - -const char* (*nvmlErrorStringFunc)(nvmlReturn_t result); -const char* nvmlErrorString(nvmlReturn_t result) { - if (nvmlErrorStringFunc == NULL) { - return "nvmlErrorString Function Not Found"; - } - return nvmlErrorStringFunc(result); -} - -nvmlReturn_t (*nvmlSystemGetDriverVersionFunc)(char *version, unsigned int length); -nvmlReturn_t nvmlSystemGetDriverVersion(char *version, unsigned int length) { - if (nvmlSystemGetDriverVersionFunc == NULL) { - return NVML_ERROR_FUNCTION_NOT_FOUND; - } - return nvmlSystemGetDriverVersionFunc(version, length); -} - -nvmlReturn_t (*nvmlDeviceGetCountFunc)(unsigned int *deviceCount); -nvmlReturn_t nvmlDeviceGetCount(unsigned int *deviceCount) { - if (nvmlDeviceGetCountFunc == NULL) { - return NVML_ERROR_FUNCTION_NOT_FOUND; - } - return nvmlDeviceGetCountFunc(deviceCount); -} - -nvmlReturn_t (*nvmlDeviceGetHandleByIndexFunc)(unsigned int index, nvmlDevice_t *device); -nvmlReturn_t nvmlDeviceGetHandleByIndex(unsigned int index, nvmlDevice_t *device) { - if (nvmlDeviceGetHandleByIndexFunc == NULL) { - return NVML_ERROR_FUNCTION_NOT_FOUND; - } - return nvmlDeviceGetHandleByIndexFunc(index, device); -} - -nvmlReturn_t (*nvmlDeviceGetMinorNumberFunc)(nvmlDevice_t device, unsigned int *minorNumber); -nvmlReturn_t nvmlDeviceGetMinorNumber(nvmlDevice_t device, unsigned int *minorNumber) { - if (nvmlDeviceGetMinorNumberFunc == NULL) { - return NVML_ERROR_FUNCTION_NOT_FOUND; - } - return nvmlDeviceGetMinorNumberFunc(device, minorNumber); -} - -nvmlReturn_t (*nvmlDeviceGetUUIDFunc)(nvmlDevice_t device, char *uuid, unsigned int length); -nvmlReturn_t nvmlDeviceGetUUID(nvmlDevice_t device, char *uuid, unsigned int length) { - if (nvmlDeviceGetUUIDFunc == NULL) { - return NVML_ERROR_FUNCTION_NOT_FOUND; - } - return nvmlDeviceGetUUIDFunc(device, uuid, length); -} - -nvmlReturn_t (*nvmlDeviceGetNameFunc)(nvmlDevice_t device, char *name, unsigned int length); -nvmlReturn_t nvmlDeviceGetName(nvmlDevice_t device, char *name, unsigned int length) { - if (nvmlDeviceGetNameFunc == NULL) { - return NVML_ERROR_FUNCTION_NOT_FOUND; - } - return nvmlDeviceGetNameFunc(device, name, length); -} - -nvmlReturn_t (*nvmlDeviceGetMemoryInfoFunc)(nvmlDevice_t device, nvmlMemory_t *memory); -nvmlReturn_t nvmlDeviceGetMemoryInfo(nvmlDevice_t device, nvmlMemory_t *memory) { - if (nvmlDeviceGetMemoryInfoFunc == NULL) { - return NVML_ERROR_FUNCTION_NOT_FOUND; - } - return nvmlDeviceGetMemoryInfoFunc(device, memory); -} - -nvmlReturn_t (*nvmlDeviceGetUtilizationRatesFunc)(nvmlDevice_t device, nvmlUtilization_t *utilization); -nvmlReturn_t nvmlDeviceGetUtilizationRates(nvmlDevice_t device, nvmlUtilization_t *utilization) { - if (nvmlDeviceGetUtilizationRatesFunc == NULL) { - return NVML_ERROR_FUNCTION_NOT_FOUND; - } - return nvmlDeviceGetUtilizationRatesFunc(device, utilization); -} - -nvmlReturn_t (*nvmlDeviceGetPowerUsageFunc)(nvmlDevice_t device, unsigned int *power); -nvmlReturn_t nvmlDeviceGetPowerUsage(nvmlDevice_t device, unsigned int *power) { - if (nvmlDeviceGetPowerUsageFunc == NULL) { - return NVML_ERROR_FUNCTION_NOT_FOUND; - } - return nvmlDeviceGetPowerUsageFunc(device, power); -} - -nvmlReturn_t (*nvmlDeviceGetTemperatureFunc)(nvmlDevice_t device, nvmlTemperatureSensors_t sensorType, unsigned int *temp); -nvmlReturn_t nvmlDeviceGetTemperature(nvmlDevice_t device, nvmlTemperatureSensors_t sensorType, unsigned int *temp) { - if (nvmlDeviceGetTemperatureFunc == NULL) { - return NVML_ERROR_FUNCTION_NOT_FOUND; - } - return nvmlDeviceGetTemperatureFunc(device, sensorType, temp); -} - -nvmlReturn_t (*nvmlDeviceGetFanSpeedFunc)(nvmlDevice_t device, unsigned int *speed); -nvmlReturn_t nvmlDeviceGetFanSpeed(nvmlDevice_t device, unsigned int *speed) { - if (nvmlDeviceGetFanSpeedFunc == NULL) { - return NVML_ERROR_FUNCTION_NOT_FOUND; - } - return nvmlDeviceGetFanSpeedFunc(device, speed); -} - -nvmlReturn_t (*nvmlDeviceGetSamplesFunc)(nvmlDevice_t device, nvmlSamplingType_t type, unsigned long long lastSeenTimeStamp, nvmlValueType_t *sampleValType, unsigned int *sampleCount, nvmlSample_t *samples); - -// Loads the "libnvidia-ml.so.1" shared library. -// Loads all symbols needed and initializes NVML. -// Call this before calling any other methods. -nvmlReturn_t nvmlInit_dl(void) { - nvmlHandle = dlopen("libnvidia-ml.so.1", RTLD_LAZY); - if (nvmlHandle == NULL) { - return NVML_ERROR_LIBRARY_NOT_FOUND; - } - nvmlInitFunc = dlsym(nvmlHandle, "nvmlInit_v2"); - if (nvmlInitFunc == NULL) { - return NVML_ERROR_FUNCTION_NOT_FOUND; - } - nvmlShutdownFunc = dlsym(nvmlHandle, "nvmlShutdown"); - if (nvmlShutdownFunc == NULL) { - return NVML_ERROR_FUNCTION_NOT_FOUND; - } - nvmlErrorStringFunc = dlsym(nvmlHandle, "nvmlErrorString"); - if (nvmlErrorStringFunc == NULL) { - return NVML_ERROR_FUNCTION_NOT_FOUND; - } - nvmlSystemGetDriverVersionFunc = dlsym(nvmlHandle, "nvmlSystemGetDriverVersion"); - if (nvmlSystemGetDriverVersionFunc == NULL) { - return NVML_ERROR_FUNCTION_NOT_FOUND; - } - nvmlDeviceGetCountFunc = dlsym(nvmlHandle, "nvmlDeviceGetCount_v2"); - if (nvmlDeviceGetCountFunc == NULL) { - return NVML_ERROR_FUNCTION_NOT_FOUND; - } - nvmlDeviceGetHandleByIndexFunc = dlsym(nvmlHandle, "nvmlDeviceGetHandleByIndex_v2"); - if (nvmlDeviceGetHandleByIndexFunc == NULL) { - return NVML_ERROR_FUNCTION_NOT_FOUND; - } - nvmlDeviceGetMinorNumberFunc = dlsym(nvmlHandle, "nvmlDeviceGetMinorNumber"); - if (nvmlDeviceGetMinorNumberFunc == NULL) { - return NVML_ERROR_FUNCTION_NOT_FOUND; - } - nvmlDeviceGetUUIDFunc = dlsym(nvmlHandle, "nvmlDeviceGetUUID"); - if (nvmlDeviceGetUUIDFunc == NULL) { - return NVML_ERROR_FUNCTION_NOT_FOUND; - } - nvmlDeviceGetNameFunc = dlsym(nvmlHandle, "nvmlDeviceGetName"); - if (nvmlDeviceGetNameFunc == NULL) { - return NVML_ERROR_FUNCTION_NOT_FOUND; - } - nvmlDeviceGetMemoryInfoFunc = dlsym(nvmlHandle, "nvmlDeviceGetMemoryInfo"); - if (nvmlDeviceGetMemoryInfoFunc == NULL) { - return NVML_ERROR_FUNCTION_NOT_FOUND; - } - nvmlDeviceGetUtilizationRatesFunc = dlsym(nvmlHandle, "nvmlDeviceGetUtilizationRates"); - if (nvmlDeviceGetUtilizationRatesFunc == NULL) { - return NVML_ERROR_FUNCTION_NOT_FOUND; - } - nvmlDeviceGetPowerUsageFunc = dlsym(nvmlHandle, "nvmlDeviceGetPowerUsage"); - if (nvmlDeviceGetPowerUsageFunc == NULL) { - return NVML_ERROR_FUNCTION_NOT_FOUND; - } - nvmlDeviceGetTemperatureFunc = dlsym(nvmlHandle, "nvmlDeviceGetTemperature"); - if (nvmlDeviceGetTemperatureFunc == NULL) { - return NVML_ERROR_FUNCTION_NOT_FOUND; - } - nvmlDeviceGetFanSpeedFunc = dlsym(nvmlHandle, "nvmlDeviceGetFanSpeed"); - if (nvmlDeviceGetFanSpeedFunc == NULL) { - return NVML_ERROR_FUNCTION_NOT_FOUND; - } - nvmlDeviceGetSamplesFunc = dlsym(nvmlHandle, "nvmlDeviceGetSamples"); - if (nvmlDeviceGetSamplesFunc == NULL) { - return NVML_ERROR_FUNCTION_NOT_FOUND; - } - nvmlReturn_t result = nvmlInitFunc(); - if (result != NVML_SUCCESS) { - dlclose(nvmlHandle); - nvmlHandle = NULL; - return result; - } - return NVML_SUCCESS; -} - -// Shuts down NVML and decrements the reference count on the dynamically loaded -// "libnvidia-ml.so.1" library. -// Call this once NVML is no longer being used. -nvmlReturn_t nvmlShutdown_dl(void) { - if (nvmlHandle == NULL) { - return NVML_SUCCESS; - } - if (nvmlShutdownFunc == NULL) { - return NVML_ERROR_FUNCTION_NOT_FOUND; - } - nvmlReturn_t r = nvmlShutdownFunc(); - if (r != NVML_SUCCESS) { - return r; - } - return (dlclose(nvmlHandle) ? NVML_ERROR_UNKNOWN : NVML_SUCCESS); -} - -// This function is here because the API provided by NVML is not very user -// friendly. This function can be used to get average utilization.gpu or -// power.draw. -// -// `device`: The identifier of the target device. -// `type`: Type of sampling event. Only NVML_TOTAL_POWER_SAMPLES and NVML_GPU_UTILIZATION_SAMPLES are supported. -// `lastSeenTimeStamp`: Return average using samples with timestamp greather than this timestamp. Unix epoch in micro seconds. -// `averageUsage`: Reference in which average is returned. -// -// In my experiments, I found that NVML_GPU_UTILIZATION_SAMPLES buffer stores -// 100 samples that are uniformly spread with ~6 samples per second. So the -// buffer stores last ~16s of data. -// NVML_TOTAL_POWER_SAMPLES buffer stores 120 samples, but in different runs I -// noticed them to be non-uniformly separated. Sometimes 120 samples only -// consisted of 10s of data and sometimes they were spread over 60s. -// -nvmlReturn_t nvmlDeviceGetAverageUsage(nvmlDevice_t device, nvmlSamplingType_t type, unsigned long long lastSeenTimeStamp, unsigned int* averageUsage) { - if (nvmlHandle == NULL) { - return NVML_ERROR_LIBRARY_NOT_FOUND; - } - if (nvmlDeviceGetSamplesFunc == NULL) { - return NVML_ERROR_FUNCTION_NOT_FOUND; - } - - // We don't really use this because both the metrics we support - // averagePowerUsage and averageGPUUtilization are unsigned int. - nvmlValueType_t sampleValType; - - // This will be set to the number of samples that can be queried. We would - // need to allocate an array of this size to store the samples. - unsigned int sampleCount; - - // Invoking this method with `samples` set to NULL sets the sampleCount. - nvmlReturn_t r = nvmlDeviceGetSamplesFunc(device, type, lastSeenTimeStamp, &sampleValType, &sampleCount, NULL); - if (r != NVML_SUCCESS) { - return r; - } - - // Allocate memory to store sampleCount samples. - // In my experiments, the sampleCount at this stage was always 120 for - // NVML_TOTAL_POWER_SAMPLES and 100 for NVML_GPU_UTILIZATION_SAMPLES - nvmlSample_t* samples = (nvmlSample_t*) malloc(sampleCount * sizeof(nvmlSample_t)); - - r = nvmlDeviceGetSamplesFunc(device, type, lastSeenTimeStamp, &sampleValType, &sampleCount, samples); - if (r != NVML_SUCCESS) { - free(samples); - return r; - } - - int i = 0; - unsigned int sum = 0; - for (; i < sampleCount; i++) { - sum += samples[i].sampleValue.uiVal; - } - *averageUsage = sum/sampleCount; - - free(samples); - return r; -} -*/ -import "C" - -import ( - "errors" - "fmt" - "time" -) - -const ( - szDriver = C.NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE - szName = C.NVML_DEVICE_NAME_BUFFER_SIZE - szUUID = C.NVML_DEVICE_UUID_BUFFER_SIZE -) - -var errLibraryNotLoaded = errors.New("could not load NVML library") - -// Initialize initializes NVML. -// Call this before calling any other methods. -func Initialize() error { - return errorString(C.nvmlInit_dl()) -} - -// Shutdown shuts down NVML. -// Call this once NVML is no longer being used. -func Shutdown() error { - return errorString(C.nvmlShutdown_dl()) -} - -// errorString takes a nvmlReturn_t and converts it into a golang error. -// It uses a nvml method to convert to a user friendly error message. -func errorString(ret C.nvmlReturn_t) error { - if ret == C.NVML_SUCCESS { - return nil - } - // We need to special case this because if nvml library is not found - // nvmlErrorString() method will not work. - if ret == C.NVML_ERROR_LIBRARY_NOT_FOUND || C.nvmlHandle == nil { - return errLibraryNotLoaded - } - err := C.GoString(C.nvmlErrorString(ret)) - return fmt.Errorf("nvml: %v", err) -} - -// SystemDriverVersion returns the the driver version on the system. -func SystemDriverVersion() (string, error) { - if C.nvmlHandle == nil { - return "", errLibraryNotLoaded - } - var driver [szDriver]C.char - r := C.nvmlSystemGetDriverVersion(&driver[0], szDriver) - return C.GoString(&driver[0]), errorString(r) -} - -// DeviceCount returns the number of nvidia devices on the system. -func DeviceCount() (uint, error) { - if C.nvmlHandle == nil { - return 0, errLibraryNotLoaded - } - var n C.uint - r := C.nvmlDeviceGetCount(&n) - return uint(n), errorString(r) -} - -// Device is the handle for the device. -// This handle is obtained by calling DeviceHandleByIndex(). -type Device struct { - dev C.nvmlDevice_t -} - -// DeviceHandleByIndex returns the device handle for a particular index. -// The indices range from 0 to DeviceCount()-1. The order in which NVML -// enumerates devices has no guarantees of consistency between reboots. -func DeviceHandleByIndex(idx uint) (Device, error) { - if C.nvmlHandle == nil { - return Device{}, errLibraryNotLoaded - } - var dev C.nvmlDevice_t - r := C.nvmlDeviceGetHandleByIndex(C.uint(idx), &dev) - return Device{dev}, errorString(r) -} - -// MinorNumber returns the minor number for the device. -// The minor number for the device is such that the Nvidia device node -// file for each GPU will have the form /dev/nvidia[minor number]. -func (d Device) MinorNumber() (uint, error) { - if C.nvmlHandle == nil { - return 0, errLibraryNotLoaded - } - var n C.uint - r := C.nvmlDeviceGetMinorNumber(d.dev, &n) - return uint(n), errorString(r) -} - -// UUID returns the globally unique immutable UUID associated with this device. -func (d Device) UUID() (string, error) { - if C.nvmlHandle == nil { - return "", errLibraryNotLoaded - } - var uuid [szUUID]C.char - r := C.nvmlDeviceGetUUID(d.dev, &uuid[0], szUUID) - return C.GoString(&uuid[0]), errorString(r) -} - -// Name returns the product name of the device. -func (d Device) Name() (string, error) { - if C.nvmlHandle == nil { - return "", errLibraryNotLoaded - } - var name [szName]C.char - r := C.nvmlDeviceGetName(d.dev, &name[0], szName) - return C.GoString(&name[0]), errorString(r) -} - -// MemoryInfo returns the total and used memory (in bytes) of the device. -func (d Device) MemoryInfo() (uint64, uint64, error) { - if C.nvmlHandle == nil { - return 0, 0, errLibraryNotLoaded - } - var memory C.nvmlMemory_t - r := C.nvmlDeviceGetMemoryInfo(d.dev, &memory) - return uint64(memory.total), uint64(memory.used), errorString(r) -} - -// UtilizationRates returns the percent of time over the past sample period during which: -// utilization.gpu: one or more kernels were executing on the GPU. -// utilization.memory: global (device) memory was being read or written. -func (d Device) UtilizationRates() (uint, uint, error) { - if C.nvmlHandle == nil { - return 0, 0, errLibraryNotLoaded - } - var utilization C.nvmlUtilization_t - r := C.nvmlDeviceGetUtilizationRates(d.dev, &utilization) - return uint(utilization.gpu), uint(utilization.memory), errorString(r) -} - -// PowerUsage returns the power usage for this GPU and its associated circuitry -// in milliwatts. The reading is accurate to within +/- 5% of current power draw. -func (d Device) PowerUsage() (uint, error) { - if C.nvmlHandle == nil { - return 0, errLibraryNotLoaded - } - var n C.uint - r := C.nvmlDeviceGetPowerUsage(d.dev, &n) - return uint(n), errorString(r) -} - -// AveragePowerUsage returns the power usage for this GPU and its associated circuitry -// in milliwatts averaged over the samples collected in the last `since` duration. -func (d Device) AveragePowerUsage(since time.Duration) (uint, error) { - if C.nvmlHandle == nil { - return 0, errLibraryNotLoaded - } - lastTs := C.ulonglong(time.Now().Add(-1*since).UnixNano() / 1000) - var n C.uint - r := C.nvmlDeviceGetAverageUsage(d.dev, C.NVML_TOTAL_POWER_SAMPLES, lastTs, &n) - return uint(n), errorString(r) -} - -// AverageGPUUtilization returns the utilization.gpu metric (percent of time -// one of more kernels were executing on the GPU) averaged over the samples -// collected in the last `since` duration. -func (d Device) AverageGPUUtilization(since time.Duration) (uint, error) { - if C.nvmlHandle == nil { - return 0, errLibraryNotLoaded - } - lastTs := C.ulonglong(time.Now().Add(-1*since).UnixNano() / 1000) - var n C.uint - r := C.nvmlDeviceGetAverageUsage(d.dev, C.NVML_GPU_UTILIZATION_SAMPLES, lastTs, &n) - return uint(n), errorString(r) -} - -// Temperature returns the temperature for this GPU in Celsius. -func (d Device) Temperature() (uint, error) { - if C.nvmlHandle == nil { - return 0, errLibraryNotLoaded - } - var n C.uint - r := C.nvmlDeviceGetTemperature(d.dev, C.NVML_TEMPERATURE_GPU, &n) - return uint(n), errorString(r) -} - -// FanSpeed returns the temperature for this GPU in the percentage of its full -// speed, with 100 being the maximum. -func (d Device) FanSpeed() (uint, error) { - if C.nvmlHandle == nil { - return 0, errLibraryNotLoaded - } - var n C.uint - r := C.nvmlDeviceGetFanSpeed(d.dev, &n) - return uint(n), errorString(r) -} diff --git a/vendor/github.com/mindprince/gonvml/nvml.h b/vendor/github.com/mindprince/gonvml/nvml.h deleted file mode 100644 index 6febac2..0000000 --- a/vendor/github.com/mindprince/gonvml/nvml.h +++ /dev/null @@ -1,5605 +0,0 @@ -/* - * Copyright 1993-2016 NVIDIA Corporation. All rights reserved. - * - * NOTICE TO USER: - * - * This source code is subject to NVIDIA ownership rights under U.S. and - * international Copyright laws. Users and possessors of this source code - * are hereby granted a nonexclusive, royalty-free license to use this code - * in individual and commercial software. - * - * NVIDIA MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE - * CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR - * IMPLIED WARRANTY OF ANY KIND. NVIDIA DISCLAIMS ALL WARRANTIES WITH - * REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. - * IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL, - * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS - * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE - * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE - * OR PERFORMANCE OF THIS SOURCE CODE. - * - * U.S. Government End Users. This source code is a "commercial item" as - * that term is defined at 48 C.F.R. 2.101 (OCT 1995), consisting of - * "commercial computer software" and "commercial computer software - * documentation" as such terms are used in 48 C.F.R. 12.212 (SEPT 1995) - * and is provided to the U.S. Government only as a commercial end item. - * Consistent with 48 C.F.R.12.212 and 48 C.F.R. 227.7202-1 through - * 227.7202-4 (JUNE 1995), all U.S. Government End Users acquire the - * source code with only those rights set forth herein. - * - * Any use of this source code in individual and commercial software must - * include, in the user documentation and internal comments to the code, - * the above Disclaimer and U.S. Government End Users Notice. - */ - -/* -NVML API Reference - -The NVIDIA Management Library (NVML) is a C-based programmatic interface for monitoring and -managing various states within NVIDIA Tesla &tm; GPUs. It is intended to be a platform for building -3rd party applications, and is also the underlying library for the NVIDIA-supported nvidia-smi -tool. NVML is thread-safe so it is safe to make simultaneous NVML calls from multiple threads. - -API Documentation - -Supported platforms: -- Windows: Windows Server 2008 R2 64bit, Windows Server 2012 R2 64bit, Windows 7 64bit, Windows 8 64bit, Windows 10 64bit -- Linux: 32-bit and 64-bit -- Hypervisors: Windows Server 2008R2/2012 Hyper-V 64bit, Citrix XenServer 6.2 SP1+, VMware ESX 5.1/5.5 - -Supported products: -- Full Support - - All Tesla products, starting with the Fermi architecture - - All Quadro products, starting with the Fermi architecture - - All GRID products, starting with the Kepler architecture - - Selected GeForce Titan products -- Limited Support - - All Geforce products, starting with the Fermi architecture - -The NVML library can be found at \%ProgramW6432\%\\"NVIDIA Corporation"\\NVSMI\\ on Windows. It is -not be added to the system path by default. To dynamically link to NVML, add this path to the PATH -environmental variable. To dynamically load NVML, call LoadLibrary with this path. - -On Linux the NVML library will be found on the standard library path. For 64 bit Linux, both the 32 bit -and 64 bit NVML libraries will be installed. - -Online documentation for this library is available at http://docs.nvidia.com/deploy/nvml-api/index.html -*/ - -#ifndef __nvml_nvml_h__ -#define __nvml_nvml_h__ - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * On Windows, set up methods for DLL export - * define NVML_STATIC_IMPORT when using nvml_loader library - */ -#if defined _WINDOWS - #if !defined NVML_STATIC_IMPORT - #if defined NVML_LIB_EXPORT - #define DECLDIR __declspec(dllexport) - #else - #define DECLDIR __declspec(dllimport) - #endif - #else - #define DECLDIR - #endif -#else - #define DECLDIR -#endif - -/** - * NVML API versioning support - */ -#define NVML_API_VERSION 8 -#define NVML_API_VERSION_STR "8" -#define nvmlInit nvmlInit_v2 -#define nvmlDeviceGetPciInfo nvmlDeviceGetPciInfo_v2 -#define nvmlDeviceGetCount nvmlDeviceGetCount_v2 -#define nvmlDeviceGetHandleByIndex nvmlDeviceGetHandleByIndex_v2 -#define nvmlDeviceGetHandleByPciBusId nvmlDeviceGetHandleByPciBusId_v2 - -/***************************************************************************************************/ -/** @defgroup nvmlDeviceStructs Device Structs - * @{ - */ -/***************************************************************************************************/ - -/** - * Special constant that some fields take when they are not available. - * Used when only part of the struct is not available. - * - * Each structure explicitly states when to check for this value. - */ -#define NVML_VALUE_NOT_AVAILABLE (-1) - -typedef struct nvmlDevice_st* nvmlDevice_t; - -/** - * Buffer size guaranteed to be large enough for pci bus id - */ -#define NVML_DEVICE_PCI_BUS_ID_BUFFER_SIZE 16 - -/** - * PCI information about a GPU device. - */ -typedef struct nvmlPciInfo_st -{ - char busId[NVML_DEVICE_PCI_BUS_ID_BUFFER_SIZE]; //!< The tuple domain:bus:device.function PCI identifier (& NULL terminator) - unsigned int domain; //!< The PCI domain on which the device's bus resides, 0 to 0xffff - unsigned int bus; //!< The bus on which the device resides, 0 to 0xff - unsigned int device; //!< The device's id on the bus, 0 to 31 - unsigned int pciDeviceId; //!< The combined 16-bit device id and 16-bit vendor id - - // Added in NVML 2.285 API - unsigned int pciSubSystemId; //!< The 32-bit Sub System Device ID - - // NVIDIA reserved for internal use only - unsigned int reserved0; - unsigned int reserved1; - unsigned int reserved2; - unsigned int reserved3; -} nvmlPciInfo_t; - -/** - * Detailed ECC error counts for a device. - * - * @deprecated Different GPU families can have different memory error counters - * See \ref nvmlDeviceGetMemoryErrorCounter - */ -typedef struct nvmlEccErrorCounts_st -{ - unsigned long long l1Cache; //!< L1 cache errors - unsigned long long l2Cache; //!< L2 cache errors - unsigned long long deviceMemory; //!< Device memory errors - unsigned long long registerFile; //!< Register file errors -} nvmlEccErrorCounts_t; - -/** - * Utilization information for a device. - * Each sample period may be between 1 second and 1/6 second, depending on the product being queried. - */ -typedef struct nvmlUtilization_st -{ - unsigned int gpu; //!< Percent of time over the past sample period during which one or more kernels was executing on the GPU - unsigned int memory; //!< Percent of time over the past sample period during which global (device) memory was being read or written -} nvmlUtilization_t; - -/** - * Memory allocation information for a device. - */ -typedef struct nvmlMemory_st -{ - unsigned long long total; //!< Total installed FB memory (in bytes) - unsigned long long free; //!< Unallocated FB memory (in bytes) - unsigned long long used; //!< Allocated FB memory (in bytes). Note that the driver/GPU always sets aside a small amount of memory for bookkeeping -} nvmlMemory_t; - -/** - * BAR1 Memory allocation Information for a device - */ -typedef struct nvmlBAR1Memory_st -{ - unsigned long long bar1Total; //!< Total BAR1 Memory (in bytes) - unsigned long long bar1Free; //!< Unallocated BAR1 Memory (in bytes) - unsigned long long bar1Used; //!< Allocated Used Memory (in bytes) -}nvmlBAR1Memory_t; - -/** - * Information about running compute processes on the GPU - */ -typedef struct nvmlProcessInfo_st -{ - unsigned int pid; //!< Process ID - unsigned long long usedGpuMemory; //!< Amount of used GPU memory in bytes. - //! Under WDDM, \ref NVML_VALUE_NOT_AVAILABLE is always reported - //! because Windows KMD manages all the memory and not the NVIDIA driver -} nvmlProcessInfo_t; - -/** - * Enum to represent type of bridge chip - */ -typedef enum nvmlBridgeChipType_enum -{ - NVML_BRIDGE_CHIP_PLX = 0, - NVML_BRIDGE_CHIP_BRO4 = 1 -}nvmlBridgeChipType_t; - -/** - * Maximum number of NvLink links supported - */ -#define NVML_NVLINK_MAX_LINKS 6 - -/** - * Enum to represent the NvLink utilization counter packet units - */ -typedef enum nvmlNvLinkUtilizationCountUnits_enum -{ - NVML_NVLINK_COUNTER_UNIT_CYCLES = 0, // count by cycles - NVML_NVLINK_COUNTER_UNIT_PACKETS = 1, // count by packets - NVML_NVLINK_COUNTER_UNIT_BYTES = 2, // count by bytes - - // this must be last - NVML_NVLINK_COUNTER_UNIT_COUNT -} nvmlNvLinkUtilizationCountUnits_t; - -/** - * Enum to represent the NvLink utilization counter packet types to count - * ** this is ONLY applicable with the units as packets or bytes - * ** as specified in \a nvmlNvLinkUtilizationCountUnits_t - * ** all packet filter descriptions are target GPU centric - * ** these can be "OR'd" together - */ -typedef enum nvmlNvLinkUtilizationCountPktTypes_enum -{ - NVML_NVLINK_COUNTER_PKTFILTER_NOP = 0x1, // no operation packets - NVML_NVLINK_COUNTER_PKTFILTER_READ = 0x2, // read packets - NVML_NVLINK_COUNTER_PKTFILTER_WRITE = 0x4, // write packets - NVML_NVLINK_COUNTER_PKTFILTER_RATOM = 0x8, // reduction atomic requests - NVML_NVLINK_COUNTER_PKTFILTER_NRATOM = 0x10, // non-reduction atomic requests - NVML_NVLINK_COUNTER_PKTFILTER_FLUSH = 0x20, // flush requests - NVML_NVLINK_COUNTER_PKTFILTER_RESPDATA = 0x40, // responses with data - NVML_NVLINK_COUNTER_PKTFILTER_RESPNODATA = 0x80, // responses without data - NVML_NVLINK_COUNTER_PKTFILTER_ALL = 0xFF // all packets -} nvmlNvLinkUtilizationCountPktTypes_t; - -/** - * Struct to define the NVLINK counter controls - */ -typedef struct nvmlNvLinkUtilizationControl_st -{ - nvmlNvLinkUtilizationCountUnits_t units; - nvmlNvLinkUtilizationCountPktTypes_t pktfilter; -} nvmlNvLinkUtilizationControl_t; - -/** - * Enum to represent NvLink queryable capabilities - */ -typedef enum nvmlNvLinkCapability_enum -{ - NVML_NVLINK_CAP_P2P_SUPPORTED = 0, // P2P over NVLink is supported - NVML_NVLINK_CAP_SYSMEM_ACCESS = 1, // Access to system memory is supported - NVML_NVLINK_CAP_P2P_ATOMICS = 2, // P2P atomics are supported - NVML_NVLINK_CAP_SYSMEM_ATOMICS= 3, // System memory atomics are supported - NVML_NVLINK_CAP_SLI_BRIDGE = 4, // SLI is supported over this link - NVML_NVLINK_CAP_VALID = 5, // Link is supported on this device - // should be last - NVML_NVLINK_CAP_COUNT -} nvmlNvLinkCapability_t; - -/** - * Enum to represent NvLink queryable error counters - */ -typedef enum nvmlNvLinkErrorCounter_enum -{ - NVML_NVLINK_ERROR_DL_REPLAY = 0, // Data link transmit replay error counter - NVML_NVLINK_ERROR_DL_RECOVERY = 1, // Data link transmit recovery error counter - NVML_NVLINK_ERROR_DL_CRC_FLIT = 2, // Data link receive flow control digit CRC error counter - NVML_NVLINK_ERROR_DL_CRC_DATA = 3, // Data link receive data CRC error counter - - // this must be last - NVML_NVLINK_ERROR_COUNT -} nvmlNvLinkErrorCounter_t; - -/** - * Represents level relationships within a system between two GPUs - * The enums are spaced to allow for future relationships - */ -typedef enum nvmlGpuLevel_enum -{ - NVML_TOPOLOGY_INTERNAL = 0, // e.g. Tesla K80 - NVML_TOPOLOGY_SINGLE = 10, // all devices that only need traverse a single PCIe switch - NVML_TOPOLOGY_MULTIPLE = 20, // all devices that need not traverse a host bridge - NVML_TOPOLOGY_HOSTBRIDGE = 30, // all devices that are connected to the same host bridge - NVML_TOPOLOGY_CPU = 40, // all devices that are connected to the same CPU but possibly multiple host bridges - NVML_TOPOLOGY_SYSTEM = 50, // all devices in the system - - // there is purposefully no COUNT here because of the need for spacing above -} nvmlGpuTopologyLevel_t; - -/* P2P Capability Index Status*/ -typedef enum nvmlGpuP2PStatus_enum -{ - NVML_P2P_STATUS_OK = 0, - NVML_P2P_STATUS_CHIPSET_NOT_SUPPORED, - NVML_P2P_STATUS_GPU_NOT_SUPPORTED, - NVML_P2P_STATUS_IOH_TOPOLOGY_NOT_SUPPORTED, - NVML_P2P_STATUS_DISABLED_BY_REGKEY, - NVML_P2P_STATUS_NOT_SUPPORTED, - NVML_P2P_STATUS_UNKNOWN - -} nvmlGpuP2PStatus_t; - -/* P2P Capability Index*/ -typedef enum nvmlGpuP2PCapsIndex_enum -{ - NVML_P2P_CAPS_INDEX_READ = 0, - NVML_P2P_CAPS_INDEX_WRITE, - NVML_P2P_CAPS_INDEX_NVLINK, - NVML_P2P_CAPS_INDEX_ATOMICS, - NVML_P2P_CAPS_INDEX_PROP, - NVML_P2P_CAPS_INDEX_UNKNOWN -}nvmlGpuP2PCapsIndex_t; - -/** - * Maximum limit on Physical Bridges per Board - */ -#define NVML_MAX_PHYSICAL_BRIDGE (128) - -/** - * Information about the Bridge Chip Firmware - */ -typedef struct nvmlBridgeChipInfo_st -{ - nvmlBridgeChipType_t type; //!< Type of Bridge Chip - unsigned int fwVersion; //!< Firmware Version. 0=Version is unavailable -}nvmlBridgeChipInfo_t; - -/** - * This structure stores the complete Hierarchy of the Bridge Chip within the board. The immediate - * bridge is stored at index 0 of bridgeInfoList, parent to immediate bridge is at index 1 and so forth. - */ -typedef struct nvmlBridgeChipHierarchy_st -{ - unsigned char bridgeCount; //!< Number of Bridge Chips on the Board - nvmlBridgeChipInfo_t bridgeChipInfo[NVML_MAX_PHYSICAL_BRIDGE]; //!< Hierarchy of Bridge Chips on the board -}nvmlBridgeChipHierarchy_t; - -/** - * Represents Type of Sampling Event - */ -typedef enum nvmlSamplingType_enum -{ - NVML_TOTAL_POWER_SAMPLES = 0, //!< To represent total power drawn by GPU - NVML_GPU_UTILIZATION_SAMPLES = 1, //!< To represent percent of time during which one or more kernels was executing on the GPU - NVML_MEMORY_UTILIZATION_SAMPLES = 2, //!< To represent percent of time during which global (device) memory was being read or written - NVML_ENC_UTILIZATION_SAMPLES = 3, //!< To represent percent of time during which NVENC remains busy - NVML_DEC_UTILIZATION_SAMPLES = 4, //!< To represent percent of time during which NVDEC remains busy - NVML_PROCESSOR_CLK_SAMPLES = 5, //!< To represent processor clock samples - NVML_MEMORY_CLK_SAMPLES = 6, //!< To represent memory clock samples - - // Keep this last - NVML_SAMPLINGTYPE_COUNT -}nvmlSamplingType_t; - -/** - * Represents the queryable PCIe utilization counters - */ -typedef enum nvmlPcieUtilCounter_enum -{ - NVML_PCIE_UTIL_TX_BYTES = 0, // 1KB granularity - NVML_PCIE_UTIL_RX_BYTES = 1, // 1KB granularity - - // Keep this last - NVML_PCIE_UTIL_COUNT -} nvmlPcieUtilCounter_t; - -/** - * Represents the type for sample value returned - */ -typedef enum nvmlValueType_enum -{ - NVML_VALUE_TYPE_DOUBLE = 0, - NVML_VALUE_TYPE_UNSIGNED_INT = 1, - NVML_VALUE_TYPE_UNSIGNED_LONG = 2, - NVML_VALUE_TYPE_UNSIGNED_LONG_LONG = 3, - NVML_VALUE_TYPE_SIGNED_LONG_LONG = 4, - - // Keep this last - NVML_VALUE_TYPE_COUNT -}nvmlValueType_t; - - -/** - * Union to represent different types of Value - */ -typedef union nvmlValue_st -{ - double dVal; //!< If the value is double - unsigned int uiVal; //!< If the value is unsigned int - unsigned long ulVal; //!< If the value is unsigned long - unsigned long long ullVal; //!< If the value is unsigned long long - signed long long sllVal; //!< If the value is signed long long -}nvmlValue_t; - -/** - * Information for Sample - */ -typedef struct nvmlSample_st -{ - unsigned long long timeStamp; //!< CPU Timestamp in microseconds - nvmlValue_t sampleValue; //!< Sample Value -}nvmlSample_t; - -/** - * Represents type of perf policy for which violation times can be queried - */ -typedef enum nvmlPerfPolicyType_enum -{ - NVML_PERF_POLICY_POWER = 0, //!< How long did power violations cause the GPU to be below application clocks - NVML_PERF_POLICY_THERMAL = 1, //!< How long did thermal violations cause the GPU to be below application clocks - NVML_PERF_POLICY_SYNC_BOOST = 2, //!< How long did sync boost cause the GPU to be below application clocks - NVML_PERF_POLICY_BOARD_LIMIT = 3, //!< How long did the board limit cause the GPU to be below application clocks - NVML_PERF_POLICY_LOW_UTILIZATION = 4, //!< How long did low utilization cause the GPU to be below application clocks - NVML_PERF_POLICY_RELIABILITY = 5, //!< How long did the board reliability limit cause the GPU to be below application clocks - - NVML_PERF_POLICY_TOTAL_APP_CLOCKS = 10, //!< Total time the GPU was held below application clocks by any limiter (0 - 5 above) - NVML_PERF_POLICY_TOTAL_BASE_CLOCKS = 11, //!< Total time the GPU was held below base clocks - - // Keep this last - NVML_PERF_POLICY_COUNT -}nvmlPerfPolicyType_t; - -/** - * Struct to hold perf policy violation status data - */ -typedef struct nvmlViolationTime_st -{ - unsigned long long referenceTime; //!< referenceTime represents CPU timestamp in microseconds - unsigned long long violationTime; //!< violationTime in Nanoseconds -}nvmlViolationTime_t; - -/** @} */ - -/***************************************************************************************************/ -/** @defgroup nvmlDeviceEnumvs Device Enums - * @{ - */ -/***************************************************************************************************/ - -/** - * Generic enable/disable enum. - */ -typedef enum nvmlEnableState_enum -{ - NVML_FEATURE_DISABLED = 0, //!< Feature disabled - NVML_FEATURE_ENABLED = 1 //!< Feature enabled -} nvmlEnableState_t; - -//! Generic flag used to specify the default behavior of some functions. See description of particular functions for details. -#define nvmlFlagDefault 0x00 -//! Generic flag used to force some behavior. See description of particular functions for details. -#define nvmlFlagForce 0x01 - -/** - * * The Brand of the GPU - * */ -typedef enum nvmlBrandType_enum -{ - NVML_BRAND_UNKNOWN = 0, - NVML_BRAND_QUADRO = 1, - NVML_BRAND_TESLA = 2, - NVML_BRAND_NVS = 3, - NVML_BRAND_GRID = 4, - NVML_BRAND_GEFORCE = 5, - - // Keep this last - NVML_BRAND_COUNT -} nvmlBrandType_t; - -/** - * Temperature thresholds. - */ -typedef enum nvmlTemperatureThresholds_enum -{ - NVML_TEMPERATURE_THRESHOLD_SHUTDOWN = 0, // Temperature at which the GPU will shut down - // for HW protection - NVML_TEMPERATURE_THRESHOLD_SLOWDOWN = 1, // Temperature at which the GPU will begin slowdown - // Keep this last - NVML_TEMPERATURE_THRESHOLD_COUNT -} nvmlTemperatureThresholds_t; - -/** - * Temperature sensors. - */ -typedef enum nvmlTemperatureSensors_enum -{ - NVML_TEMPERATURE_GPU = 0, //!< Temperature sensor for the GPU die - - // Keep this last - NVML_TEMPERATURE_COUNT -} nvmlTemperatureSensors_t; - -/** - * Compute mode. - * - * NVML_COMPUTEMODE_EXCLUSIVE_PROCESS was added in CUDA 4.0. - * Earlier CUDA versions supported a single exclusive mode, - * which is equivalent to NVML_COMPUTEMODE_EXCLUSIVE_THREAD in CUDA 4.0 and beyond. - */ -typedef enum nvmlComputeMode_enum -{ - NVML_COMPUTEMODE_DEFAULT = 0, //!< Default compute mode -- multiple contexts per device - NVML_COMPUTEMODE_EXCLUSIVE_THREAD = 1, //!< Support Removed - NVML_COMPUTEMODE_PROHIBITED = 2, //!< Compute-prohibited mode -- no contexts per device - NVML_COMPUTEMODE_EXCLUSIVE_PROCESS = 3, //!< Compute-exclusive-process mode -- only one context per device, usable from multiple threads at a time - - // Keep this last - NVML_COMPUTEMODE_COUNT -} nvmlComputeMode_t; - -/** - * ECC bit types. - * - * @deprecated See \ref nvmlMemoryErrorType_t for a more flexible type - */ -#define nvmlEccBitType_t nvmlMemoryErrorType_t - -/** - * Single bit ECC errors - * - * @deprecated Mapped to \ref NVML_MEMORY_ERROR_TYPE_CORRECTED - */ -#define NVML_SINGLE_BIT_ECC NVML_MEMORY_ERROR_TYPE_CORRECTED - -/** - * Double bit ECC errors - * - * @deprecated Mapped to \ref NVML_MEMORY_ERROR_TYPE_UNCORRECTED - */ -#define NVML_DOUBLE_BIT_ECC NVML_MEMORY_ERROR_TYPE_UNCORRECTED - -/** - * Memory error types - */ -typedef enum nvmlMemoryErrorType_enum -{ - /** - * A memory error that was corrected - * - * For ECC errors, these are single bit errors - * For Texture memory, these are errors fixed by resend - */ - NVML_MEMORY_ERROR_TYPE_CORRECTED = 0, - /** - * A memory error that was not corrected - * - * For ECC errors, these are double bit errors - * For Texture memory, these are errors where the resend fails - */ - NVML_MEMORY_ERROR_TYPE_UNCORRECTED = 1, - - - // Keep this last - NVML_MEMORY_ERROR_TYPE_COUNT //!< Count of memory error types - -} nvmlMemoryErrorType_t; - -/** - * ECC counter types. - * - * Note: Volatile counts are reset each time the driver loads. On Windows this is once per boot. On Linux this can be more frequent. - * On Linux the driver unloads when no active clients exist. If persistence mode is enabled or there is always a driver - * client active (e.g. X11), then Linux also sees per-boot behavior. If not, volatile counts are reset each time a compute app - * is run. - */ -typedef enum nvmlEccCounterType_enum -{ - NVML_VOLATILE_ECC = 0, //!< Volatile counts are reset each time the driver loads. - NVML_AGGREGATE_ECC = 1, //!< Aggregate counts persist across reboots (i.e. for the lifetime of the device) - - // Keep this last - NVML_ECC_COUNTER_TYPE_COUNT //!< Count of memory counter types -} nvmlEccCounterType_t; - -/** - * Clock types. - * - * All speeds are in Mhz. - */ -typedef enum nvmlClockType_enum -{ - NVML_CLOCK_GRAPHICS = 0, //!< Graphics clock domain - NVML_CLOCK_SM = 1, //!< SM clock domain - NVML_CLOCK_MEM = 2, //!< Memory clock domain - NVML_CLOCK_VIDEO = 3, //!< Video encoder/decoder clock domain - - // Keep this last - NVML_CLOCK_COUNT //usedGpuMemory is not supported - - - unsigned long long time; //!< Amount of time in ms during which the compute context was active. The time is reported as 0 if - //!< the process is not terminated - - unsigned long long startTime; //!< CPU Timestamp in usec representing start time for the process - - unsigned int isRunning; //!< Flag to represent if the process is running (1 for running, 0 for terminated) - - unsigned int reserved[5]; //!< Reserved for future use -} nvmlAccountingStats_t; - -/** @} */ - -/***************************************************************************************************/ -/** @defgroup nvmlVgpuConstants Vgpu Constants - * @{ - */ -/***************************************************************************************************/ - -/** - * Buffer size guaranteed to be large enough for \ref nvmlVgpuTypeGetLicense - */ -#define NVML_GRID_LICENSE_BUFFER_SIZE 128 - -#define NVML_VGPU_NAME_BUFFER_SIZE 64 - -#define NVML_MAX_VGPU_TYPES_PER_PGPU 17 - -#define NVML_MAX_VGPU_INSTANCES_PER_PGPU 24 - -#define NVML_GRID_LICENSE_FEATURE_MAX_COUNT 3 - -#define NVML_GRID_LICENSE_INFO_MAX_LENGTH 128 - -/** @} */ - -/***************************************************************************************************/ -/** @defgroup nvmlVgpuEnum Vgpu Enum - * @{ - */ -/***************************************************************************************************/ - -/*! - * Types of VM identifiers - */ -typedef enum nvmlVgpuVmIdType { - NVML_VGPU_VM_ID_DOMAIN_ID = 0, //!< VM ID represents DOMAIN ID - NVML_VGPU_VM_ID_UUID = 1, //!< VM ID represents UUID -} nvmlVgpuVmIdType_t; - -// vGPU GUEST info state. -typedef enum nvmlVgpuGuestInfoState_enum -{ - NVML_VGPU_INSTANCE_GUEST_INFO_STATE_UNINITIALIZED = 0, //= 0 and < \a unitCount - * @param unit Reference in which to return the unit handle - * - * @return - * - \ref NVML_SUCCESS if \a unit has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a index is invalid or \a unit is NULL - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlUnitGetHandleByIndex(unsigned int index, nvmlUnit_t *unit); - -/** - * Retrieves the static information associated with a unit. - * - * For S-class products. - * - * See \ref nvmlUnitInfo_t for details on available unit info. - * - * @param unit The identifier of the target unit - * @param info Reference in which to return the unit information - * - * @return - * - \ref NVML_SUCCESS if \a info has been populated - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unit is invalid or \a info is NULL - */ -nvmlReturn_t DECLDIR nvmlUnitGetUnitInfo(nvmlUnit_t unit, nvmlUnitInfo_t *info); - -/** - * Retrieves the LED state associated with this unit. - * - * For S-class products. - * - * See \ref nvmlLedState_t for details on allowed states. - * - * @param unit The identifier of the target unit - * @param state Reference in which to return the current LED state - * - * @return - * - \ref NVML_SUCCESS if \a state has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unit is invalid or \a state is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if this is not an S-class product - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlUnitSetLedState() - */ -nvmlReturn_t DECLDIR nvmlUnitGetLedState(nvmlUnit_t unit, nvmlLedState_t *state); - -/** - * Retrieves the PSU stats for the unit. - * - * For S-class products. - * - * See \ref nvmlPSUInfo_t for details on available PSU info. - * - * @param unit The identifier of the target unit - * @param psu Reference in which to return the PSU information - * - * @return - * - \ref NVML_SUCCESS if \a psu has been populated - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unit is invalid or \a psu is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if this is not an S-class product - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlUnitGetPsuInfo(nvmlUnit_t unit, nvmlPSUInfo_t *psu); - -/** - * Retrieves the temperature readings for the unit, in degrees C. - * - * For S-class products. - * - * Depending on the product, readings may be available for intake (type=0), - * exhaust (type=1) and board (type=2). - * - * @param unit The identifier of the target unit - * @param type The type of reading to take - * @param temp Reference in which to return the intake temperature - * - * @return - * - \ref NVML_SUCCESS if \a temp has been populated - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unit or \a type is invalid or \a temp is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if this is not an S-class product - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlUnitGetTemperature(nvmlUnit_t unit, unsigned int type, unsigned int *temp); - -/** - * Retrieves the fan speed readings for the unit. - * - * For S-class products. - * - * See \ref nvmlUnitFanSpeeds_t for details on available fan speed info. - * - * @param unit The identifier of the target unit - * @param fanSpeeds Reference in which to return the fan speed information - * - * @return - * - \ref NVML_SUCCESS if \a fanSpeeds has been populated - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unit is invalid or \a fanSpeeds is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if this is not an S-class product - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlUnitGetFanSpeedInfo(nvmlUnit_t unit, nvmlUnitFanSpeeds_t *fanSpeeds); - -/** - * Retrieves the set of GPU devices that are attached to the specified unit. - * - * For S-class products. - * - * The \a deviceCount argument is expected to be set to the size of the input \a devices array. - * - * @param unit The identifier of the target unit - * @param deviceCount Reference in which to provide the \a devices array size, and - * to return the number of attached GPU devices - * @param devices Reference in which to return the references to the attached GPU devices - * - * @return - * - \ref NVML_SUCCESS if \a deviceCount and \a devices have been populated - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a deviceCount indicates that the \a devices array is too small - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unit is invalid, either of \a deviceCount or \a devices is NULL - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlUnitGetDevices(nvmlUnit_t unit, unsigned int *deviceCount, nvmlDevice_t *devices); - -/** - * Retrieves the IDs and firmware versions for any Host Interface Cards (HICs) in the system. - * - * For S-class products. - * - * The \a hwbcCount argument is expected to be set to the size of the input \a hwbcEntries array. - * The HIC must be connected to an S-class system for it to be reported by this function. - * - * @param hwbcCount Size of hwbcEntries array - * @param hwbcEntries Array holding information about hwbc - * - * @return - * - \ref NVML_SUCCESS if \a hwbcCount and \a hwbcEntries have been populated - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if either \a hwbcCount or \a hwbcEntries is NULL - * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a hwbcCount indicates that the \a hwbcEntries array is too small - */ -nvmlReturn_t DECLDIR nvmlSystemGetHicVersion(unsigned int *hwbcCount, nvmlHwbcEntry_t *hwbcEntries); -/** @} */ - -/***************************************************************************************************/ -/** @defgroup nvmlDeviceQueries Device Queries - * This chapter describes that queries that NVML can perform against each device. - * In each case the device is identified with an nvmlDevice_t handle. This handle is obtained by - * calling one of \ref nvmlDeviceGetHandleByIndex(), \ref nvmlDeviceGetHandleBySerial(), - * \ref nvmlDeviceGetHandleByPciBusId(). or \ref nvmlDeviceGetHandleByUUID(). - * @{ - */ -/***************************************************************************************************/ - - /** - * Retrieves the number of compute devices in the system. A compute device is a single GPU. - * - * For all products. - * - * Note: New nvmlDeviceGetCount_v2 (default in NVML 5.319) returns count of all devices in the system - * even if nvmlDeviceGetHandleByIndex_v2 returns NVML_ERROR_NO_PERMISSION for such device. - * Update your code to handle this error, or use NVML 4.304 or older nvml header file. - * For backward binary compatibility reasons _v1 version of the API is still present in the shared - * library. - * Old _v1 version of nvmlDeviceGetCount doesn't count devices that NVML has no permission to talk to. - * - * @param deviceCount Reference in which to return the number of accessible devices - * - * @return - * - \ref NVML_SUCCESS if \a deviceCount has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a deviceCount is NULL - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetCount(unsigned int *deviceCount); - -/** - * Acquire the handle for a particular device, based on its index. - * - * For all products. - * - * Valid indices are derived from the \a accessibleDevices count returned by - * \ref nvmlDeviceGetCount(). For example, if \a accessibleDevices is 2 the valid indices - * are 0 and 1, corresponding to GPU 0 and GPU 1. - * - * The order in which NVML enumerates devices has no guarantees of consistency between reboots. For that reason it - * is recommended that devices be looked up by their PCI ids or UUID. See - * \ref nvmlDeviceGetHandleByUUID() and \ref nvmlDeviceGetHandleByPciBusId(). - * - * Note: The NVML index may not correlate with other APIs, such as the CUDA device index. - * - * Starting from NVML 5, this API causes NVML to initialize the target GPU - * NVML may initialize additional GPUs if: - * - The target GPU is an SLI slave - * - * Note: New nvmlDeviceGetCount_v2 (default in NVML 5.319) returns count of all devices in the system - * even if nvmlDeviceGetHandleByIndex_v2 returns NVML_ERROR_NO_PERMISSION for such device. - * Update your code to handle this error, or use NVML 4.304 or older nvml header file. - * For backward binary compatibility reasons _v1 version of the API is still present in the shared - * library. - * Old _v1 version of nvmlDeviceGetCount doesn't count devices that NVML has no permission to talk to. - * - * This means that nvmlDeviceGetHandleByIndex_v2 and _v1 can return different devices for the same index. - * If you don't touch macros that map old (_v1) versions to _v2 versions at the top of the file you don't - * need to worry about that. - * - * @param index The index of the target GPU, >= 0 and < \a accessibleDevices - * @param device Reference in which to return the device handle - * - * @return - * - \ref NVML_SUCCESS if \a device has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a index is invalid or \a device is NULL - * - \ref NVML_ERROR_INSUFFICIENT_POWER if any attached devices have improperly attached external power cables - * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to talk to this device - * - \ref NVML_ERROR_IRQ_ISSUE if NVIDIA kernel detected an interrupt issue with the attached GPUs - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlDeviceGetIndex - * @see nvmlDeviceGetCount - */ -nvmlReturn_t DECLDIR nvmlDeviceGetHandleByIndex(unsigned int index, nvmlDevice_t *device); - -/** - * Acquire the handle for a particular device, based on its board serial number. - * - * For Fermi &tm; or newer fully supported devices. - * - * This number corresponds to the value printed directly on the board, and to the value returned by - * \ref nvmlDeviceGetSerial(). - * - * @deprecated Since more than one GPU can exist on a single board this function is deprecated in favor - * of \ref nvmlDeviceGetHandleByUUID. - * For dual GPU boards this function will return NVML_ERROR_INVALID_ARGUMENT. - * - * Starting from NVML 5, this API causes NVML to initialize the target GPU - * NVML may initialize additional GPUs as it searches for the target GPU - * - * @param serial The board serial number of the target GPU - * @param device Reference in which to return the device handle - * - * @return - * - \ref NVML_SUCCESS if \a device has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a serial is invalid, \a device is NULL or more than one - * device has the same serial (dual GPU boards) - * - \ref NVML_ERROR_NOT_FOUND if \a serial does not match a valid device on the system - * - \ref NVML_ERROR_INSUFFICIENT_POWER if any attached devices have improperly attached external power cables - * - \ref NVML_ERROR_IRQ_ISSUE if NVIDIA kernel detected an interrupt issue with the attached GPUs - * - \ref NVML_ERROR_GPU_IS_LOST if any GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlDeviceGetSerial - * @see nvmlDeviceGetHandleByUUID - */ -nvmlReturn_t DECLDIR nvmlDeviceGetHandleBySerial(const char *serial, nvmlDevice_t *device); - -/** - * Acquire the handle for a particular device, based on its globally unique immutable UUID associated with each device. - * - * For all products. - * - * @param uuid The UUID of the target GPU - * @param device Reference in which to return the device handle - * - * Starting from NVML 5, this API causes NVML to initialize the target GPU - * NVML may initialize additional GPUs as it searches for the target GPU - * - * @return - * - \ref NVML_SUCCESS if \a device has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a uuid is invalid or \a device is null - * - \ref NVML_ERROR_NOT_FOUND if \a uuid does not match a valid device on the system - * - \ref NVML_ERROR_INSUFFICIENT_POWER if any attached devices have improperly attached external power cables - * - \ref NVML_ERROR_IRQ_ISSUE if NVIDIA kernel detected an interrupt issue with the attached GPUs - * - \ref NVML_ERROR_GPU_IS_LOST if any GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlDeviceGetUUID - */ -nvmlReturn_t DECLDIR nvmlDeviceGetHandleByUUID(const char *uuid, nvmlDevice_t *device); - -/** - * Acquire the handle for a particular device, based on its PCI bus id. - * - * For all products. - * - * This value corresponds to the nvmlPciInfo_t::busId returned by \ref nvmlDeviceGetPciInfo(). - * - * Starting from NVML 5, this API causes NVML to initialize the target GPU - * NVML may initialize additional GPUs if: - * - The target GPU is an SLI slave - * - * \note NVML 4.304 and older version of nvmlDeviceGetHandleByPciBusId"_v1" returns NVML_ERROR_NOT_FOUND - * instead of NVML_ERROR_NO_PERMISSION. - * - * @param pciBusId The PCI bus id of the target GPU - * @param device Reference in which to return the device handle - * - * @return - * - \ref NVML_SUCCESS if \a device has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a pciBusId is invalid or \a device is NULL - * - \ref NVML_ERROR_NOT_FOUND if \a pciBusId does not match a valid device on the system - * - \ref NVML_ERROR_INSUFFICIENT_POWER if the attached device has improperly attached external power cables - * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to talk to this device - * - \ref NVML_ERROR_IRQ_ISSUE if NVIDIA kernel detected an interrupt issue with the attached GPUs - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetHandleByPciBusId(const char *pciBusId, nvmlDevice_t *device); - -/** - * Retrieves the name of this device. - * - * For all products. - * - * The name is an alphanumeric string that denotes a particular product, e.g. Tesla &tm; C2070. It will not - * exceed 64 characters in length (including the NULL terminator). See \ref - * nvmlConstants::NVML_DEVICE_NAME_BUFFER_SIZE. - * - * @param device The identifier of the target device - * @param name Reference in which to return the product name - * @param length The maximum allowed length of the string returned in \a name - * - * @return - * - \ref NVML_SUCCESS if \a name has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a name is NULL - * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetName(nvmlDevice_t device, char *name, unsigned int length); - -/** - * Retrieves the brand of this device. - * - * For all products. - * - * The type is a member of \ref nvmlBrandType_t defined above. - * - * @param device The identifier of the target device - * @param type Reference in which to return the product brand type - * - * @return - * - \ref NVML_SUCCESS if \a name has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a type is NULL - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetBrand(nvmlDevice_t device, nvmlBrandType_t *type); - -/** - * Retrieves the NVML index of this device. - * - * For all products. - * - * Valid indices are derived from the \a accessibleDevices count returned by - * \ref nvmlDeviceGetCount(). For example, if \a accessibleDevices is 2 the valid indices - * are 0 and 1, corresponding to GPU 0 and GPU 1. - * - * The order in which NVML enumerates devices has no guarantees of consistency between reboots. For that reason it - * is recommended that devices be looked up by their PCI ids or GPU UUID. See - * \ref nvmlDeviceGetHandleByPciBusId() and \ref nvmlDeviceGetHandleByUUID(). - * - * Note: The NVML index may not correlate with other APIs, such as the CUDA device index. - * - * @param device The identifier of the target device - * @param index Reference in which to return the NVML index of the device - * - * @return - * - \ref NVML_SUCCESS if \a index has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a index is NULL - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlDeviceGetHandleByIndex() - * @see nvmlDeviceGetCount() - */ -nvmlReturn_t DECLDIR nvmlDeviceGetIndex(nvmlDevice_t device, unsigned int *index); - -/** - * Retrieves the globally unique board serial number associated with this device's board. - * - * For all products with an inforom. - * - * The serial number is an alphanumeric string that will not exceed 30 characters (including the NULL terminator). - * This number matches the serial number tag that is physically attached to the board. See \ref - * nvmlConstants::NVML_DEVICE_SERIAL_BUFFER_SIZE. - * - * @param device The identifier of the target device - * @param serial Reference in which to return the board/module serial number - * @param length The maximum allowed length of the string returned in \a serial - * - * @return - * - \ref NVML_SUCCESS if \a serial has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a serial is NULL - * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetSerial(nvmlDevice_t device, char *serial, unsigned int length); - -/** - * Retrieves an array of unsigned ints (sized to cpuSetSize) of bitmasks with the ideal CPU affinity for the device - * For example, if processors 0, 1, 32, and 33 are ideal for the device and cpuSetSize == 2, - * result[0] = 0x3, result[1] = 0x3 - * - * For Kepler &tm; or newer fully supported devices. - * Supported on Linux only. - * - * @param device The identifier of the target device - * @param cpuSetSize The size of the cpuSet array that is safe to access - * @param cpuSet Array reference in which to return a bitmask of CPUs, 64 CPUs per - * unsigned long on 64-bit machines, 32 on 32-bit machines - * - * @return - * - \ref NVML_SUCCESS if \a cpuAffinity has been filled - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, cpuSetSize == 0, or cpuSet is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetCpuAffinity(nvmlDevice_t device, unsigned int cpuSetSize, unsigned long *cpuSet); - -/** - * Sets the ideal affinity for the calling thread and device using the guidelines - * given in nvmlDeviceGetCpuAffinity(). Note, this is a change as of version 8.0. - * Older versions set the affinity for a calling process and all children. - * Currently supports up to 64 processors. - * - * For Kepler &tm; or newer fully supported devices. - * Supported on Linux only. - * - * @param device The identifier of the target device - * - * @return - * - \ref NVML_SUCCESS if the calling process has been successfully bound - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceSetCpuAffinity(nvmlDevice_t device); - -/** - * Clear all affinity bindings for the calling thread. Note, this is a change as of version - * 8.0 as older versions cleared the affinity for a calling process and all children. - * - * For Kepler &tm; or newer fully supported devices. - * Supported on Linux only. - * - * @param device The identifier of the target device - * - * @return - * - \ref NVML_SUCCESS if the calling process has been successfully unbound - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceClearCpuAffinity(nvmlDevice_t device); - -/** - * Retrieve the common ancestor for two devices - * For all products. - * Supported on Linux only. - * - * @param device1 The identifier of the first device - * @param device2 The identifier of the second device - * @param pathInfo A \ref nvmlGpuTopologyLevel_t that gives the path type - * - * @return - * - \ref NVML_SUCCESS if \a pathInfo has been set - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device1, or \a device2 is invalid, or \a pathInfo is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device or OS does not support this feature - * - \ref NVML_ERROR_UNKNOWN an error has occurred in underlying topology discovery - */ -nvmlReturn_t DECLDIR nvmlDeviceGetTopologyCommonAncestor(nvmlDevice_t device1, nvmlDevice_t device2, nvmlGpuTopologyLevel_t *pathInfo); - -/** - * Retrieve the set of GPUs that are nearest to a given device at a specific interconnectivity level - * For all products. - * Supported on Linux only. - * - * @param device The identifier of the first device - * @param level The \ref nvmlGpuTopologyLevel_t level to search for other GPUs - * @param count When zero, is set to the number of matching GPUs such that \a deviceArray - * can be malloc'd. When non-zero, \a deviceArray will be filled with \a count - * number of device handles. - * @param deviceArray An array of device handles for GPUs found at \a level - * - * @return - * - \ref NVML_SUCCESS if \a deviceArray or \a count (if initially zero) has been set - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a level, or \a count is invalid, or \a deviceArray is NULL with a non-zero \a count - * - \ref NVML_ERROR_NOT_SUPPORTED if the device or OS does not support this feature - * - \ref NVML_ERROR_UNKNOWN an error has occurred in underlying topology discovery - */ -nvmlReturn_t DECLDIR nvmlDeviceGetTopologyNearestGpus(nvmlDevice_t device, nvmlGpuTopologyLevel_t level, unsigned int *count, nvmlDevice_t *deviceArray); - -/** - * Retrieve the set of GPUs that have a CPU affinity with the given CPU number - * For all products. - * Supported on Linux only. - * - * @param cpuNumber The CPU number - * @param count When zero, is set to the number of matching GPUs such that \a deviceArray - * can be malloc'd. When non-zero, \a deviceArray will be filled with \a count - * number of device handles. - * @param deviceArray An array of device handles for GPUs found with affinity to \a cpuNumber - * - * @return - * - \ref NVML_SUCCESS if \a deviceArray or \a count (if initially zero) has been set - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a cpuNumber, or \a count is invalid, or \a deviceArray is NULL with a non-zero \a count - * - \ref NVML_ERROR_NOT_SUPPORTED if the device or OS does not support this feature - * - \ref NVML_ERROR_UNKNOWN an error has occurred in underlying topology discovery - */ -nvmlReturn_t DECLDIR nvmlSystemGetTopologyGpuSet(unsigned int cpuNumber, unsigned int *count, nvmlDevice_t *deviceArray); - -/** - * Retrieve the status for a given p2p capability index between a given pair of GPU - * - * @param device1 The first device - * @param device2 The second device - * @param p2pIndex p2p Capability Index being looked for between \a device1 and \a device2 - * @param p2pStatus Reference in which to return the status of the \a p2pIndex - * between \a device1 and \a device2 - * @return - * - \ref NVML_SUCCESS if \a p2pStatus has been populated - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device1 or \a device2 or \a p2pIndex is invalid or \a p2pStatus is NULL - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetP2PStatus(nvmlDevice_t device1, nvmlDevice_t device2, nvmlGpuP2PCapsIndex_t p2pIndex,nvmlGpuP2PStatus_t *p2pStatus); - -/** - * Retrieves the globally unique immutable UUID associated with this device, as a 5 part hexadecimal string, - * that augments the immutable, board serial identifier. - * - * For all products. - * - * The UUID is a globally unique identifier. It is the only available identifier for pre-Fermi-architecture products. - * It does NOT correspond to any identifier printed on the board. It will not exceed 80 characters in length - * (including the NULL terminator). See \ref nvmlConstants::NVML_DEVICE_UUID_BUFFER_SIZE. - * - * @param device The identifier of the target device - * @param uuid Reference in which to return the GPU UUID - * @param length The maximum allowed length of the string returned in \a uuid - * - * @return - * - \ref NVML_SUCCESS if \a uuid has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a uuid is NULL - * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetUUID(nvmlDevice_t device, char *uuid, unsigned int length); - -/** - * Retrieves minor number for the device. The minor number for the device is such that the Nvidia device node file for - * each GPU will have the form /dev/nvidia[minor number]. - * - * For all products. - * Supported only for Linux - * - * @param device The identifier of the target device - * @param minorNumber Reference in which to return the minor number for the device - * @return - * - \ref NVML_SUCCESS if the minor number is successfully retrieved - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a minorNumber is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetMinorNumber(nvmlDevice_t device, unsigned int *minorNumber); - -/** - * Retrieves the the device board part number which is programmed into the board's InfoROM - * - * For all products. - * - * @param device Identifier of the target device - * @param partNumber Reference to the buffer to return - * @param length Length of the buffer reference - * - * @return - * - \ref NVML_SUCCESS if \a partNumber has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_NOT_SUPPORTED if the needed VBIOS fields have not been filled - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a serial is NULL - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetBoardPartNumber(nvmlDevice_t device, char* partNumber, unsigned int length); - -/** - * Retrieves the version information for the device's infoROM object. - * - * For all products with an inforom. - * - * Fermi and higher parts have non-volatile on-board memory for persisting device info, such as aggregate - * ECC counts. The version of the data structures in this memory may change from time to time. It will not - * exceed 16 characters in length (including the NULL terminator). - * See \ref nvmlConstants::NVML_DEVICE_INFOROM_VERSION_BUFFER_SIZE. - * - * See \ref nvmlInforomObject_t for details on the available infoROM objects. - * - * @param device The identifier of the target device - * @param object The target infoROM object - * @param version Reference in which to return the infoROM version - * @param length The maximum allowed length of the string returned in \a version - * - * @return - * - \ref NVML_SUCCESS if \a version has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a version is NULL - * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have an infoROM - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlDeviceGetInforomImageVersion - */ -nvmlReturn_t DECLDIR nvmlDeviceGetInforomVersion(nvmlDevice_t device, nvmlInforomObject_t object, char *version, unsigned int length); - -/** - * Retrieves the global infoROM image version - * - * For all products with an inforom. - * - * Image version just like VBIOS version uniquely describes the exact version of the infoROM flashed on the board - * in contrast to infoROM object version which is only an indicator of supported features. - * Version string will not exceed 16 characters in length (including the NULL terminator). - * See \ref nvmlConstants::NVML_DEVICE_INFOROM_VERSION_BUFFER_SIZE. - * - * @param device The identifier of the target device - * @param version Reference in which to return the infoROM image version - * @param length The maximum allowed length of the string returned in \a version - * - * @return - * - \ref NVML_SUCCESS if \a version has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a version is NULL - * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have an infoROM - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlDeviceGetInforomVersion - */ -nvmlReturn_t DECLDIR nvmlDeviceGetInforomImageVersion(nvmlDevice_t device, char *version, unsigned int length); - -/** - * Retrieves the checksum of the configuration stored in the device's infoROM. - * - * For all products with an inforom. - * - * Can be used to make sure that two GPUs have the exact same configuration. - * Current checksum takes into account configuration stored in PWR and ECC infoROM objects. - * Checksum can change between driver releases or when user changes configuration (e.g. disable/enable ECC) - * - * @param device The identifier of the target device - * @param checksum Reference in which to return the infoROM configuration checksum - * - * @return - * - \ref NVML_SUCCESS if \a checksum has been set - * - \ref NVML_ERROR_CORRUPTED_INFOROM if the device's checksum couldn't be retrieved due to infoROM corruption - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a checksum is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetInforomConfigurationChecksum(nvmlDevice_t device, unsigned int *checksum); - -/** - * Reads the infoROM from the flash and verifies the checksums. - * - * For all products with an inforom. - * - * @param device The identifier of the target device - * - * @return - * - \ref NVML_SUCCESS if infoROM is not corrupted - * - \ref NVML_ERROR_CORRUPTED_INFOROM if the device's infoROM is corrupted - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceValidateInforom(nvmlDevice_t device); - -/** - * Retrieves the display mode for the device. - * - * For all products. - * - * This method indicates whether a physical display (e.g. monitor) is currently connected to - * any of the device's connectors. - * - * See \ref nvmlEnableState_t for details on allowed modes. - * - * @param device The identifier of the target device - * @param display Reference in which to return the display mode - * - * @return - * - \ref NVML_SUCCESS if \a display has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a display is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetDisplayMode(nvmlDevice_t device, nvmlEnableState_t *display); - -/** - * Retrieves the display active state for the device. - * - * For all products. - * - * This method indicates whether a display is initialized on the device. - * For example whether X Server is attached to this device and has allocated memory for the screen. - * - * Display can be active even when no monitor is physically attached. - * - * See \ref nvmlEnableState_t for details on allowed modes. - * - * @param device The identifier of the target device - * @param isActive Reference in which to return the display active state - * - * @return - * - \ref NVML_SUCCESS if \a isActive has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a isActive is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetDisplayActive(nvmlDevice_t device, nvmlEnableState_t *isActive); - -/** - * Retrieves the persistence mode associated with this device. - * - * For all products. - * For Linux only. - * - * When driver persistence mode is enabled the driver software state is not torn down when the last - * client disconnects. By default this feature is disabled. - * - * See \ref nvmlEnableState_t for details on allowed modes. - * - * @param device The identifier of the target device - * @param mode Reference in which to return the current driver persistence mode - * - * @return - * - \ref NVML_SUCCESS if \a mode has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a mode is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlDeviceSetPersistenceMode() - */ -nvmlReturn_t DECLDIR nvmlDeviceGetPersistenceMode(nvmlDevice_t device, nvmlEnableState_t *mode); - -/** - * Retrieves the PCI attributes of this device. - * - * For all products. - * - * See \ref nvmlPciInfo_t for details on the available PCI info. - * - * @param device The identifier of the target device - * @param pci Reference in which to return the PCI info - * - * @return - * - \ref NVML_SUCCESS if \a pci has been populated - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a pci is NULL - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetPciInfo(nvmlDevice_t device, nvmlPciInfo_t *pci); - -/** - * Retrieves the maximum PCIe link generation possible with this device and system - * - * I.E. for a generation 2 PCIe device attached to a generation 1 PCIe bus the max link generation this function will - * report is generation 1. - * - * For Fermi &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param maxLinkGen Reference in which to return the max PCIe link generation - * - * @return - * - \ref NVML_SUCCESS if \a maxLinkGen has been populated - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a maxLinkGen is null - * - \ref NVML_ERROR_NOT_SUPPORTED if PCIe link information is not available - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetMaxPcieLinkGeneration(nvmlDevice_t device, unsigned int *maxLinkGen); - -/** - * Retrieves the maximum PCIe link width possible with this device and system - * - * I.E. for a device with a 16x PCIe bus width attached to a 8x PCIe system bus this function will report - * a max link width of 8. - * - * For Fermi &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param maxLinkWidth Reference in which to return the max PCIe link generation - * - * @return - * - \ref NVML_SUCCESS if \a maxLinkWidth has been populated - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a maxLinkWidth is null - * - \ref NVML_ERROR_NOT_SUPPORTED if PCIe link information is not available - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetMaxPcieLinkWidth(nvmlDevice_t device, unsigned int *maxLinkWidth); - -/** - * Retrieves the current PCIe link generation - * - * For Fermi &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param currLinkGen Reference in which to return the current PCIe link generation - * - * @return - * - \ref NVML_SUCCESS if \a currLinkGen has been populated - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a currLinkGen is null - * - \ref NVML_ERROR_NOT_SUPPORTED if PCIe link information is not available - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetCurrPcieLinkGeneration(nvmlDevice_t device, unsigned int *currLinkGen); - -/** - * Retrieves the current PCIe link width - * - * For Fermi &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param currLinkWidth Reference in which to return the current PCIe link generation - * - * @return - * - \ref NVML_SUCCESS if \a currLinkWidth has been populated - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a currLinkWidth is null - * - \ref NVML_ERROR_NOT_SUPPORTED if PCIe link information is not available - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetCurrPcieLinkWidth(nvmlDevice_t device, unsigned int *currLinkWidth); - -/** - * Retrieve PCIe utilization information. - * This function is querying a byte counter over a 20ms interval and thus is the - * PCIe throughput over that interval. - * - * For Maxwell &tm; or newer fully supported devices. - * - * This method is not supported in virtual machines running virtual GPU (vGPU). - * - * @param device The identifier of the target device - * @param counter The specific counter that should be queried \ref nvmlPcieUtilCounter_t - * @param value Reference in which to return throughput in KB/s - * - * @return - * - \ref NVML_SUCCESS if \a value has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a counter is invalid, or \a value is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetPcieThroughput(nvmlDevice_t device, nvmlPcieUtilCounter_t counter, unsigned int *value); - -/** - * Retrieve the PCIe replay counter. - * - * For Kepler &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param value Reference in which to return the counter's value - * - * @return - * - \ref NVML_SUCCESS if \a value and \a rollover have been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a value or \a rollover are NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetPcieReplayCounter(nvmlDevice_t device, unsigned int *value); - -/** - * Retrieves the current clock speeds for the device. - * - * For Fermi &tm; or newer fully supported devices. - * - * See \ref nvmlClockType_t for details on available clock information. - * - * @param device The identifier of the target device - * @param type Identify which clock domain to query - * @param clock Reference in which to return the clock speed in MHz - * - * @return - * - \ref NVML_SUCCESS if \a clock has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a clock is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device cannot report the specified clock - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetClockInfo(nvmlDevice_t device, nvmlClockType_t type, unsigned int *clock); - -/** - * Retrieves the maximum clock speeds for the device. - * - * For Fermi &tm; or newer fully supported devices. - * - * See \ref nvmlClockType_t for details on available clock information. - * - * \note On GPUs from Fermi family current P0 clocks (reported by \ref nvmlDeviceGetClockInfo) can differ from max clocks - * by few MHz. - * - * @param device The identifier of the target device - * @param type Identify which clock domain to query - * @param clock Reference in which to return the clock speed in MHz - * - * @return - * - \ref NVML_SUCCESS if \a clock has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a clock is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device cannot report the specified clock - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetMaxClockInfo(nvmlDevice_t device, nvmlClockType_t type, unsigned int *clock); - -/** - * Retrieves the current setting of a clock that applications will use unless an overspec situation occurs. - * Can be changed using \ref nvmlDeviceSetApplicationsClocks. - * - * For Kepler &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param clockType Identify which clock domain to query - * @param clockMHz Reference in which to return the clock in MHz - * - * @return - * - \ref NVML_SUCCESS if \a clockMHz has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a clockMHz is NULL or \a clockType is invalid - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetApplicationsClock(nvmlDevice_t device, nvmlClockType_t clockType, unsigned int *clockMHz); - -/** - * Retrieves the default applications clock that GPU boots with or - * defaults to after \ref nvmlDeviceResetApplicationsClocks call. - * - * For Kepler &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param clockType Identify which clock domain to query - * @param clockMHz Reference in which to return the default clock in MHz - * - * @return - * - \ref NVML_SUCCESS if \a clockMHz has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a clockMHz is NULL or \a clockType is invalid - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * \see nvmlDeviceGetApplicationsClock - */ -nvmlReturn_t DECLDIR nvmlDeviceGetDefaultApplicationsClock(nvmlDevice_t device, nvmlClockType_t clockType, unsigned int *clockMHz); - -/** - * Resets the application clock to the default value - * - * This is the applications clock that will be used after system reboot or driver reload. - * Default value is constant, but the current value an be changed using \ref nvmlDeviceSetApplicationsClocks. - * - * On Pascal and newer hardware, if clocks were previously locked with \ref nvmlDeviceSetApplicationsClocks, - * this call will unlock clocks. This returns clocks their default behavior ofautomatically boosting above - * base clocks as thermal limits allow. - * - * @see nvmlDeviceGetApplicationsClock - * @see nvmlDeviceSetApplicationsClocks - * - * For Fermi &tm; or newer non-GeForce fully supported devices and Maxwell or newer GeForce devices. - * - * @param device The identifier of the target device - * - * @return - * - \ref NVML_SUCCESS if new settings were successfully set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceResetApplicationsClocks(nvmlDevice_t device); - -/** - * Retrieves the clock speed for the clock specified by the clock type and clock ID. - * - * For Kepler &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param clockType Identify which clock domain to query - * @param clockId Identify which clock in the domain to query - * @param clockMHz Reference in which to return the clock in MHz - * - * @return - * - \ref NVML_SUCCESS if \a clockMHz has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a clockMHz is NULL or \a clockType is invalid - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetClock(nvmlDevice_t device, nvmlClockType_t clockType, nvmlClockId_t clockId, unsigned int *clockMHz); - -/** - * Retrieves the customer defined maximum boost clock speed specified by the given clock type. - * - * For Pascal &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param clockType Identify which clock domain to query - * @param clockMHz Reference in which to return the clock in MHz - * - * @return - * - \ref NVML_SUCCESS if \a clockMHz has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a clockMHz is NULL or \a clockType is invalid - * - \ref NVML_ERROR_NOT_SUPPORTED if the device or the \a clockType on this device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetMaxCustomerBoostClock(nvmlDevice_t device, nvmlClockType_t clockType, unsigned int *clockMHz); - -/** - * Retrieves the list of possible memory clocks that can be used as an argument for \ref nvmlDeviceSetApplicationsClocks. - * - * For Kepler &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param count Reference in which to provide the \a clocksMHz array size, and - * to return the number of elements - * @param clocksMHz Reference in which to return the clock in MHz - * - * @return - * - \ref NVML_SUCCESS if \a count and \a clocksMHz have been populated - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a count is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a count is too small (\a count is set to the number of - * required elements) - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlDeviceSetApplicationsClocks - * @see nvmlDeviceGetSupportedGraphicsClocks - */ -nvmlReturn_t DECLDIR nvmlDeviceGetSupportedMemoryClocks(nvmlDevice_t device, unsigned int *count, unsigned int *clocksMHz); - -/** - * Retrieves the list of possible graphics clocks that can be used as an argument for \ref nvmlDeviceSetApplicationsClocks. - * - * For Kepler &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param memoryClockMHz Memory clock for which to return possible graphics clocks - * @param count Reference in which to provide the \a clocksMHz array size, and - * to return the number of elements - * @param clocksMHz Reference in which to return the clocks in MHz - * - * @return - * - \ref NVML_SUCCESS if \a count and \a clocksMHz have been populated - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_NOT_FOUND if the specified \a memoryClockMHz is not a supported frequency - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a clock is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a count is too small - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlDeviceSetApplicationsClocks - * @see nvmlDeviceGetSupportedMemoryClocks - */ -nvmlReturn_t DECLDIR nvmlDeviceGetSupportedGraphicsClocks(nvmlDevice_t device, unsigned int memoryClockMHz, unsigned int *count, unsigned int *clocksMHz); - -/** - * Retrieve the current state of Auto Boosted clocks on a device and store it in \a isEnabled - * - * For Kepler &tm; or newer fully supported devices. - * - * Auto Boosted clocks are enabled by default on some hardware, allowing the GPU to run at higher clock rates - * to maximize performance as thermal limits allow. - * - * On Pascal and newer hardware, Auto Aoosted clocks are controlled through application clocks. - * Use \ref nvmlDeviceSetApplicationsClocks and \ref nvmlDeviceResetApplicationsClocks to control Auto Boost - * behavior. - * - * @param device The identifier of the target device - * @param isEnabled Where to store the current state of Auto Boosted clocks of the target device - * @param defaultIsEnabled Where to store the default Auto Boosted clocks behavior of the target device that the device will - * revert to when no applications are using the GPU - * - * @return - * - \ref NVML_SUCCESS If \a isEnabled has been been set with the Auto Boosted clocks state of \a device - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a isEnabled is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support Auto Boosted clocks - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - */ -nvmlReturn_t DECLDIR nvmlDeviceGetAutoBoostedClocksEnabled(nvmlDevice_t device, nvmlEnableState_t *isEnabled, nvmlEnableState_t *defaultIsEnabled); - -/** - * Try to set the current state of Auto Boosted clocks on a device. - * - * For Kepler &tm; or newer fully supported devices. - * - * Auto Boosted clocks are enabled by default on some hardware, allowing the GPU to run at higher clock rates - * to maximize performance as thermal limits allow. Auto Boosted clocks should be disabled if fixed clock - * rates are desired. - * - * Non-root users may use this API by default but can be restricted by root from using this API by calling - * \ref nvmlDeviceSetAPIRestriction with apiType=NVML_RESTRICTED_API_SET_AUTO_BOOSTED_CLOCKS. - * Note: Persistence Mode is required to modify current Auto Boost settings, therefore, it must be enabled. - * - * On Pascal and newer hardware, Auto Boosted clocks are controlled through application clocks. - * Use \ref nvmlDeviceSetApplicationsClocks and \ref nvmlDeviceResetApplicationsClocks to control Auto Boost - * behavior. - * - * @param device The identifier of the target device - * @param enabled What state to try to set Auto Boosted clocks of the target device to - * - * @return - * - \ref NVML_SUCCESS If the Auto Boosted clocks were successfully set to the state specified by \a enabled - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support Auto Boosted clocks - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - */ -nvmlReturn_t DECLDIR nvmlDeviceSetAutoBoostedClocksEnabled(nvmlDevice_t device, nvmlEnableState_t enabled); - -/** - * Try to set the default state of Auto Boosted clocks on a device. This is the default state that Auto Boosted clocks will - * return to when no compute running processes (e.g. CUDA application which have an active context) are running - * - * For Kepler &tm; or newer non-GeForce fully supported devices and Maxwell or newer GeForce devices. - * Requires root/admin permissions. - * - * Auto Boosted clocks are enabled by default on some hardware, allowing the GPU to run at higher clock rates - * to maximize performance as thermal limits allow. Auto Boosted clocks should be disabled if fixed clock - * rates are desired. - * - * On Pascal and newer hardware, Auto Boosted clocks are controlled through application clocks. - * Use \ref nvmlDeviceSetApplicationsClocks and \ref nvmlDeviceResetApplicationsClocks to control Auto Boost - * behavior. - * - * @param device The identifier of the target device - * @param enabled What state to try to set default Auto Boosted clocks of the target device to - * @param flags Flags that change the default behavior. Currently Unused. - * - * @return - * - \ref NVML_SUCCESS If the Auto Boosted clock's default state was successfully set to the state specified by \a enabled - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_NO_PERMISSION If the calling user does not have permission to change Auto Boosted clock's default state. - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support Auto Boosted clocks - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - */ -nvmlReturn_t DECLDIR nvmlDeviceSetDefaultAutoBoostedClocksEnabled(nvmlDevice_t device, nvmlEnableState_t enabled, unsigned int flags); - - -/** - * Retrieves the intended operating speed of the device's fan. - * - * Note: The reported speed is the intended fan speed. If the fan is physically blocked and unable to spin, the - * output will not match the actual fan speed. - * - * For all discrete products with dedicated fans. - * - * The fan speed is expressed as a percent of the maximum, i.e. full speed is 100%. - * - * @param device The identifier of the target device - * @param speed Reference in which to return the fan speed percentage - * - * @return - * - \ref NVML_SUCCESS if \a speed has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a speed is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have a fan - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetFanSpeed(nvmlDevice_t device, unsigned int *speed); - -/** - * Retrieves the current temperature readings for the device, in degrees C. - * - * For all products. - * - * See \ref nvmlTemperatureSensors_t for details on available temperature sensors. - * - * @param device The identifier of the target device - * @param sensorType Flag that indicates which sensor reading to retrieve - * @param temp Reference in which to return the temperature reading - * - * @return - * - \ref NVML_SUCCESS if \a temp has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a sensorType is invalid or \a temp is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have the specified sensor - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetTemperature(nvmlDevice_t device, nvmlTemperatureSensors_t sensorType, unsigned int *temp); - -/** - * Retrieves the temperature threshold for the GPU with the specified threshold type in degrees C. - * - * For Kepler &tm; or newer fully supported devices. - * - * See \ref nvmlTemperatureThresholds_t for details on available temperature thresholds. - * - * @param device The identifier of the target device - * @param thresholdType The type of threshold value queried - * @param temp Reference in which to return the temperature reading - * @return - * - \ref NVML_SUCCESS if \a temp has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a thresholdType is invalid or \a temp is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have a temperature sensor or is unsupported - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetTemperatureThreshold(nvmlDevice_t device, nvmlTemperatureThresholds_t thresholdType, unsigned int *temp); - -/** - * Retrieves the current performance state for the device. - * - * For Fermi &tm; or newer fully supported devices. - * - * See \ref nvmlPstates_t for details on allowed performance states. - * - * @param device The identifier of the target device - * @param pState Reference in which to return the performance state reading - * - * @return - * - \ref NVML_SUCCESS if \a pState has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a pState is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetPerformanceState(nvmlDevice_t device, nvmlPstates_t *pState); - -/** - * Retrieves current clocks throttling reasons. - * - * For all fully supported products. - * - * \note More than one bit can be enabled at the same time. Multiple reasons can be affecting clocks at once. - * - * @param device The identifier of the target device - * @param clocksThrottleReasons Reference in which to return bitmask of active clocks throttle - * reasons - * - * @return - * - \ref NVML_SUCCESS if \a clocksThrottleReasons has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a clocksThrottleReasons is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlClocksThrottleReasons - * @see nvmlDeviceGetSupportedClocksThrottleReasons - */ -nvmlReturn_t DECLDIR nvmlDeviceGetCurrentClocksThrottleReasons(nvmlDevice_t device, unsigned long long *clocksThrottleReasons); - -/** - * Retrieves bitmask of supported clocks throttle reasons that can be returned by - * \ref nvmlDeviceGetCurrentClocksThrottleReasons - * - * For all fully supported products. - * - * This method is not supported in virtual machines running virtual GPU (vGPU). - * - * @param device The identifier of the target device - * @param supportedClocksThrottleReasons Reference in which to return bitmask of supported - * clocks throttle reasons - * - * @return - * - \ref NVML_SUCCESS if \a supportedClocksThrottleReasons has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a supportedClocksThrottleReasons is NULL - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlClocksThrottleReasons - * @see nvmlDeviceGetCurrentClocksThrottleReasons - */ -nvmlReturn_t DECLDIR nvmlDeviceGetSupportedClocksThrottleReasons(nvmlDevice_t device, unsigned long long *supportedClocksThrottleReasons); - -/** - * Deprecated: Use \ref nvmlDeviceGetPerformanceState. This function exposes an incorrect generalization. - * - * Retrieve the current performance state for the device. - * - * For Fermi &tm; or newer fully supported devices. - * - * See \ref nvmlPstates_t for details on allowed performance states. - * - * @param device The identifier of the target device - * @param pState Reference in which to return the performance state reading - * - * @return - * - \ref NVML_SUCCESS if \a pState has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a pState is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetPowerState(nvmlDevice_t device, nvmlPstates_t *pState); - -/** - * This API has been deprecated. - * - * Retrieves the power management mode associated with this device. - * - * For products from the Fermi family. - * - Requires \a NVML_INFOROM_POWER version 3.0 or higher. - * - * For from the Kepler or newer families. - * - Does not require \a NVML_INFOROM_POWER object. - * - * This flag indicates whether any power management algorithm is currently active on the device. An - * enabled state does not necessarily mean the device is being actively throttled -- only that - * that the driver will do so if the appropriate conditions are met. - * - * See \ref nvmlEnableState_t for details on allowed modes. - * - * @param device The identifier of the target device - * @param mode Reference in which to return the current power management mode - * - * @return - * - \ref NVML_SUCCESS if \a mode has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a mode is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetPowerManagementMode(nvmlDevice_t device, nvmlEnableState_t *mode); - -/** - * Retrieves the power management limit associated with this device. - * - * For Fermi &tm; or newer fully supported devices. - * - * The power limit defines the upper boundary for the card's power draw. If - * the card's total power draw reaches this limit the power management algorithm kicks in. - * - * This reading is only available if power management mode is supported. - * See \ref nvmlDeviceGetPowerManagementMode. - * - * @param device The identifier of the target device - * @param limit Reference in which to return the power management limit in milliwatts - * - * @return - * - \ref NVML_SUCCESS if \a limit has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a limit is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetPowerManagementLimit(nvmlDevice_t device, unsigned int *limit); - -/** - * Retrieves information about possible values of power management limits on this device. - * - * For Kepler &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param minLimit Reference in which to return the minimum power management limit in milliwatts - * @param maxLimit Reference in which to return the maximum power management limit in milliwatts - * - * @return - * - \ref NVML_SUCCESS if \a minLimit and \a maxLimit have been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a minLimit or \a maxLimit is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlDeviceSetPowerManagementLimit - */ -nvmlReturn_t DECLDIR nvmlDeviceGetPowerManagementLimitConstraints(nvmlDevice_t device, unsigned int *minLimit, unsigned int *maxLimit); - -/** - * Retrieves default power management limit on this device, in milliwatts. - * Default power management limit is a power management limit that the device boots with. - * - * For Kepler &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param defaultLimit Reference in which to return the default power management limit in milliwatts - * - * @return - * - \ref NVML_SUCCESS if \a defaultLimit has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a defaultLimit is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetPowerManagementDefaultLimit(nvmlDevice_t device, unsigned int *defaultLimit); - -/** - * Retrieves power usage for this GPU in milliwatts and its associated circuitry (e.g. memory) - * - * For Fermi &tm; or newer fully supported devices. - * - * On Fermi and Kepler GPUs the reading is accurate to within +/- 5% of current power draw. - * - * It is only available if power management mode is supported. See \ref nvmlDeviceGetPowerManagementMode. - * - * @param device The identifier of the target device - * @param power Reference in which to return the power usage information - * - * @return - * - \ref NVML_SUCCESS if \a power has been populated - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a power is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support power readings - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetPowerUsage(nvmlDevice_t device, unsigned int *power); - -/** - * Retrieves total energy consumption for this GPU in millijoules (mJ) since the driver was last reloaded - * - * For newer than Pascal &tm; fully supported devices. - * - * @param device The identifier of the target device - * @param energy Reference in which to return the energy consumption information - * - * @return - * - \ref NVML_SUCCESS if \a energy has been populated - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a energy is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support energy readings - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetTotalEnergyConsumption(nvmlDevice_t device, unsigned long long *energy); - -/** - * Get the effective power limit that the driver enforces after taking into account all limiters - * - * Note: This can be different from the \ref nvmlDeviceGetPowerManagementLimit if other limits are set elsewhere - * This includes the out of band power limit interface - * - * For Kepler &tm; or newer fully supported devices. - * - * @param device The device to communicate with - * @param limit Reference in which to return the power management limit in milliwatts - * - * @return - * - \ref NVML_SUCCESS if \a limit has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a limit is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetEnforcedPowerLimit(nvmlDevice_t device, unsigned int *limit); - -/** - * Retrieves the current GOM and pending GOM (the one that GPU will switch to after reboot). - * - * For GK110 M-class and X-class Tesla &tm; products from the Kepler family. - * Modes \ref NVML_GOM_LOW_DP and \ref NVML_GOM_ALL_ON are supported on fully supported GeForce products. - * Not supported on Quadro ® and Tesla &tm; C-class products. - * - * @param device The identifier of the target device - * @param current Reference in which to return the current GOM - * @param pending Reference in which to return the pending GOM - * - * @return - * - \ref NVML_SUCCESS if \a mode has been populated - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a current or \a pending is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlGpuOperationMode_t - * @see nvmlDeviceSetGpuOperationMode - */ -nvmlReturn_t DECLDIR nvmlDeviceGetGpuOperationMode(nvmlDevice_t device, nvmlGpuOperationMode_t *current, nvmlGpuOperationMode_t *pending); - -/** - * Retrieves the amount of used, free and total memory available on the device, in bytes. - * - * For all products. - * - * Enabling ECC reduces the amount of total available memory, due to the extra required parity bits. - * Under WDDM most device memory is allocated and managed on startup by Windows. - * - * Under Linux and Windows TCC, the reported amount of used memory is equal to the sum of memory allocated - * by all active channels on the device. - * - * See \ref nvmlMemory_t for details on available memory info. - * - * @param device The identifier of the target device - * @param memory Reference in which to return the memory information - * - * @return - * - \ref NVML_SUCCESS if \a memory has been populated - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a memory is NULL - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetMemoryInfo(nvmlDevice_t device, nvmlMemory_t *memory); - -/** - * Retrieves the current compute mode for the device. - * - * For all products. - * - * See \ref nvmlComputeMode_t for details on allowed compute modes. - * - * @param device The identifier of the target device - * @param mode Reference in which to return the current compute mode - * - * @return - * - \ref NVML_SUCCESS if \a mode has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a mode is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlDeviceSetComputeMode() - */ -nvmlReturn_t DECLDIR nvmlDeviceGetComputeMode(nvmlDevice_t device, nvmlComputeMode_t *mode); - -/** - * Retrieves the CUDA compute capability of the device. - * - * For all products. - * - * Returns the major and minor compute capability version numbers of the - * device. The major and minor versions are equivalent to the - * CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR and - * CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR attributes that would be - * returned by CUDA's cuDeviceGetAttribute(). - * - * @param device The identifier of the target device - * @param major Reference in which to return the major CUDA compute capability - * @param minor Reference in which to return the minor CUDA compute capability - * - * @return - * - \ref NVML_SUCCESS if \a major and \a minor have been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a major or \a minor are NULL - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetCudaComputeCapability(nvmlDevice_t device, int *major, int *minor); - -/** - * Retrieves the current and pending ECC modes for the device. - * - * For Fermi &tm; or newer fully supported devices. - * Only applicable to devices with ECC. - * Requires \a NVML_INFOROM_ECC version 1.0 or higher. - * - * Changing ECC modes requires a reboot. The "pending" ECC mode refers to the target mode following - * the next reboot. - * - * See \ref nvmlEnableState_t for details on allowed modes. - * - * @param device The identifier of the target device - * @param current Reference in which to return the current ECC mode - * @param pending Reference in which to return the pending ECC mode - * - * @return - * - \ref NVML_SUCCESS if \a current and \a pending have been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or either \a current or \a pending is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlDeviceSetEccMode() - */ -nvmlReturn_t DECLDIR nvmlDeviceGetEccMode(nvmlDevice_t device, nvmlEnableState_t *current, nvmlEnableState_t *pending); - -/** - * Retrieves the device boardId from 0-N. - * Devices with the same boardId indicate GPUs connected to the same PLX. Use in conjunction with - * \ref nvmlDeviceGetMultiGpuBoard() to decide if they are on the same board as well. - * The boardId returned is a unique ID for the current configuration. Uniqueness and ordering across - * reboots and system configurations is not guaranteed (i.e. if a Tesla K40c returns 0x100 and - * the two GPUs on a Tesla K10 in the same system returns 0x200 it is not guaranteed they will - * always return those values but they will always be different from each other). - * - * - * For Fermi &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param boardId Reference in which to return the device's board ID - * - * @return - * - \ref NVML_SUCCESS if \a boardId has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a boardId is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetBoardId(nvmlDevice_t device, unsigned int *boardId); - -/** - * Retrieves whether the device is on a Multi-GPU Board - * Devices that are on multi-GPU boards will set \a multiGpuBool to a non-zero value. - * - * For Fermi &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param multiGpuBool Reference in which to return a zero or non-zero value - * to indicate whether the device is on a multi GPU board - * - * @return - * - \ref NVML_SUCCESS if \a multiGpuBool has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a multiGpuBool is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetMultiGpuBoard(nvmlDevice_t device, unsigned int *multiGpuBool); - -/** - * Retrieves the total ECC error counts for the device. - * - * For Fermi &tm; or newer fully supported devices. - * Only applicable to devices with ECC. - * Requires \a NVML_INFOROM_ECC version 1.0 or higher. - * Requires ECC Mode to be enabled. - * - * The total error count is the sum of errors across each of the separate memory systems, i.e. the total set of - * errors across the entire device. - * - * See \ref nvmlMemoryErrorType_t for a description of available error types.\n - * See \ref nvmlEccCounterType_t for a description of available counter types. - * - * @param device The identifier of the target device - * @param errorType Flag that specifies the type of the errors. - * @param counterType Flag that specifies the counter-type of the errors. - * @param eccCounts Reference in which to return the specified ECC errors - * - * @return - * - \ref NVML_SUCCESS if \a eccCounts has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a errorType or \a counterType is invalid, or \a eccCounts is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlDeviceClearEccErrorCounts() - */ -nvmlReturn_t DECLDIR nvmlDeviceGetTotalEccErrors(nvmlDevice_t device, nvmlMemoryErrorType_t errorType, nvmlEccCounterType_t counterType, unsigned long long *eccCounts); - -/** - * Retrieves the detailed ECC error counts for the device. - * - * @deprecated This API supports only a fixed set of ECC error locations - * On different GPU architectures different locations are supported - * See \ref nvmlDeviceGetMemoryErrorCounter - * - * For Fermi &tm; or newer fully supported devices. - * Only applicable to devices with ECC. - * Requires \a NVML_INFOROM_ECC version 2.0 or higher to report aggregate location-based ECC counts. - * Requires \a NVML_INFOROM_ECC version 1.0 or higher to report all other ECC counts. - * Requires ECC Mode to be enabled. - * - * Detailed errors provide separate ECC counts for specific parts of the memory system. - * - * Reports zero for unsupported ECC error counters when a subset of ECC error counters are supported. - * - * See \ref nvmlMemoryErrorType_t for a description of available bit types.\n - * See \ref nvmlEccCounterType_t for a description of available counter types.\n - * See \ref nvmlEccErrorCounts_t for a description of provided detailed ECC counts. - * - * @param device The identifier of the target device - * @param errorType Flag that specifies the type of the errors. - * @param counterType Flag that specifies the counter-type of the errors. - * @param eccCounts Reference in which to return the specified ECC errors - * - * @return - * - \ref NVML_SUCCESS if \a eccCounts has been populated - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a errorType or \a counterType is invalid, or \a eccCounts is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlDeviceClearEccErrorCounts() - */ -nvmlReturn_t DECLDIR nvmlDeviceGetDetailedEccErrors(nvmlDevice_t device, nvmlMemoryErrorType_t errorType, nvmlEccCounterType_t counterType, nvmlEccErrorCounts_t *eccCounts); - -/** - * Retrieves the requested memory error counter for the device. - * - * For Fermi &tm; or newer fully supported devices. - * Requires \a NVML_INFOROM_ECC version 2.0 or higher to report aggregate location-based memory error counts. - * Requires \a NVML_INFOROM_ECC version 1.0 or higher to report all other memory error counts. - * - * Only applicable to devices with ECC. - * - * Requires ECC Mode to be enabled. - * - * See \ref nvmlMemoryErrorType_t for a description of available memory error types.\n - * See \ref nvmlEccCounterType_t for a description of available counter types.\n - * See \ref nvmlMemoryLocation_t for a description of available counter locations.\n - * - * @param device The identifier of the target device - * @param errorType Flag that specifies the type of error. - * @param counterType Flag that specifies the counter-type of the errors. - * @param locationType Specifies the location of the counter. - * @param count Reference in which to return the ECC counter - * - * @return - * - \ref NVML_SUCCESS if \a count has been populated - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a bitTyp,e \a counterType or \a locationType is - * invalid, or \a count is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support ECC error reporting in the specified memory - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetMemoryErrorCounter(nvmlDevice_t device, nvmlMemoryErrorType_t errorType, - nvmlEccCounterType_t counterType, - nvmlMemoryLocation_t locationType, unsigned long long *count); - -/** - * Retrieves the current utilization rates for the device's major subsystems. - * - * For Fermi &tm; or newer fully supported devices. - * - * See \ref nvmlUtilization_t for details on available utilization rates. - * - * \note During driver initialization when ECC is enabled one can see high GPU and Memory Utilization readings. - * This is caused by ECC Memory Scrubbing mechanism that is performed during driver initialization. - * - * @param device The identifier of the target device - * @param utilization Reference in which to return the utilization information - * - * @return - * - \ref NVML_SUCCESS if \a utilization has been populated - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a utilization is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetUtilizationRates(nvmlDevice_t device, nvmlUtilization_t *utilization); - -/** - * Retrieves the current utilization and sampling size in microseconds for the Encoder - * - * For Kepler &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param utilization Reference to an unsigned int for encoder utilization info - * @param samplingPeriodUs Reference to an unsigned int for the sampling period in US - * - * @return - * - \ref NVML_SUCCESS if \a utilization has been populated - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a utilization is NULL, or \a samplingPeriodUs is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetEncoderUtilization(nvmlDevice_t device, unsigned int *utilization, unsigned int *samplingPeriodUs); - -/** - * Retrieves the current capacity of the device's encoder, in macroblocks per second. - * - * For Maxwell &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param encoderQueryType Type of encoder to query - * @param encoderCapacity Reference to an unsigned int for the encoder capacity - * - * @return - * - \ref NVML_SUCCESS if \a encoderCapacity is fetched - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a encoderCapacity is NULL, or \a device or \a encoderQueryType - * are invalid - * - \ref NVML_ERROR_NOT_SUPPORTED if device does not support the encoder specified in \a encodeQueryType - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetEncoderCapacity (nvmlDevice_t device, nvmlEncoderType_t encoderQueryType, unsigned int *encoderCapacity); - -/** - * Retrieves the current encoder statistics for a given device. - * - * For Maxwell &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param sessionCount Reference to an unsigned int for count of active encoder sessions - * @param averageFps Reference to an unsigned int for trailing average FPS of all active sessions - * @param averageLatency Reference to an unsigned int for encode latency in microseconds - * - * @return - * - \ref NVML_SUCCESS if \a sessionCount, \a averageFps and \a averageLatency is fetched - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a sessionCount, or \a device or \a averageFps, - * or \a averageLatency is NULL - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetEncoderStats (nvmlDevice_t device, unsigned int *sessionCount, - unsigned int *averageFps, unsigned int *averageLatency); - -/** - * Retrieves information about active encoder sessions on a target device. - * - * An array of active encoder sessions is returned in the caller-supplied buffer pointed at by \a sessionInfos. The - * array elememt count is passed in \a sessionCount, and \a sessionCount is used to return the number of sessions - * written to the buffer. - * - * If the supplied buffer is not large enough to accomodate the active session array, the function returns - * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlEncoderSessionInfo_t array required in \a sessionCount. - * To query the number of active encoder sessions, call this function with *sessionCount = 0. The code will return - * NVML_SUCCESS with number of active encoder sessions updated in *sessionCount. - * - * For Maxwell &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param sessionCount Reference to caller supplied array size, and returns the number of sessions. - * @param sessionInfos Reference in which to return the session information - * - * @return - * - \ref NVML_SUCCESS if \a sessionInfos is fetched - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a sessionCount is too small, array element count is returned in \a sessionCount - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a sessionCount is NULL. - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetEncoderSessions(nvmlDevice_t device, unsigned int *sessionCount, nvmlEncoderSessionInfo_t *sessionInfos); - -/** - * Retrieves the current utilization and sampling size in microseconds for the Decoder - * - * For Kepler &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param utilization Reference to an unsigned int for decoder utilization info - * @param samplingPeriodUs Reference to an unsigned int for the sampling period in US - * - * @return - * - \ref NVML_SUCCESS if \a utilization has been populated - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a utilization is NULL, or \a samplingPeriodUs is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetDecoderUtilization(nvmlDevice_t device, unsigned int *utilization, unsigned int *samplingPeriodUs); - -/** - * Retrieves the current and pending driver model for the device. - * - * For Fermi &tm; or newer fully supported devices. - * For windows only. - * - * On Windows platforms the device driver can run in either WDDM or WDM (TCC) mode. If a display is attached - * to the device it must run in WDDM mode. TCC mode is preferred if a display is not attached. - * - * See \ref nvmlDriverModel_t for details on available driver models. - * - * @param device The identifier of the target device - * @param current Reference in which to return the current driver model - * @param pending Reference in which to return the pending driver model - * - * @return - * - \ref NVML_SUCCESS if either \a current and/or \a pending have been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or both \a current and \a pending are NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the platform is not windows - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlDeviceSetDriverModel() - */ -nvmlReturn_t DECLDIR nvmlDeviceGetDriverModel(nvmlDevice_t device, nvmlDriverModel_t *current, nvmlDriverModel_t *pending); - -/** - * Get VBIOS version of the device. - * - * For all products. - * - * The VBIOS version may change from time to time. It will not exceed 32 characters in length - * (including the NULL terminator). See \ref nvmlConstants::NVML_DEVICE_VBIOS_VERSION_BUFFER_SIZE. - * - * @param device The identifier of the target device - * @param version Reference to which to return the VBIOS version - * @param length The maximum allowed length of the string returned in \a version - * - * @return - * - \ref NVML_SUCCESS if \a version has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a version is NULL - * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetVbiosVersion(nvmlDevice_t device, char *version, unsigned int length); - -/** - * Get Bridge Chip Information for all the bridge chips on the board. - * - * For all fully supported products. - * Only applicable to multi-GPU products. - * - * @param device The identifier of the target device - * @param bridgeHierarchy Reference to the returned bridge chip Hierarchy - * - * @return - * - \ref NVML_SUCCESS if bridge chip exists - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a bridgeInfo is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if bridge chip not supported on the device - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - */ -nvmlReturn_t DECLDIR nvmlDeviceGetBridgeChipInfo(nvmlDevice_t device, nvmlBridgeChipHierarchy_t *bridgeHierarchy); - -/** - * Get information about processes with a compute context on a device - * - * For Fermi &tm; or newer fully supported devices. - * - * This function returns information only about compute running processes (e.g. CUDA application which have - * active context). Any graphics applications (e.g. using OpenGL, DirectX) won't be listed by this function. - * - * To query the current number of running compute processes, call this function with *infoCount = 0. The - * return code will be NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if none are running. For this call - * \a infos is allowed to be NULL. - * - * The usedGpuMemory field returned is all of the memory used by the application. - * - * Keep in mind that information returned by this call is dynamic and the number of elements might change in - * time. Allocate more space for \a infos table in case new compute processes are spawned. - * - * @param device The identifier of the target device - * @param infoCount Reference in which to provide the \a infos array size, and - * to return the number of returned elements - * @param infos Reference in which to return the process information - * - * @return - * - \ref NVML_SUCCESS if \a infoCount and \a infos have been populated - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a infoCount indicates that the \a infos array is too small - * \a infoCount will contain minimal amount of space necessary for - * the call to complete - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, either of \a infoCount or \a infos is NULL - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see \ref nvmlSystemGetProcessName - */ -nvmlReturn_t DECLDIR nvmlDeviceGetComputeRunningProcesses(nvmlDevice_t device, unsigned int *infoCount, nvmlProcessInfo_t *infos); - -/** - * Get information about processes with a graphics context on a device - * - * For Kepler &tm; or newer fully supported devices. - * - * This function returns information only about graphics based processes - * (eg. applications using OpenGL, DirectX) - * - * To query the current number of running graphics processes, call this function with *infoCount = 0. The - * return code will be NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if none are running. For this call - * \a infos is allowed to be NULL. - * - * The usedGpuMemory field returned is all of the memory used by the application. - * - * Keep in mind that information returned by this call is dynamic and the number of elements might change in - * time. Allocate more space for \a infos table in case new graphics processes are spawned. - * - * @param device The identifier of the target device - * @param infoCount Reference in which to provide the \a infos array size, and - * to return the number of returned elements - * @param infos Reference in which to return the process information - * - * @return - * - \ref NVML_SUCCESS if \a infoCount and \a infos have been populated - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a infoCount indicates that the \a infos array is too small - * \a infoCount will contain minimal amount of space necessary for - * the call to complete - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, either of \a infoCount or \a infos is NULL - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see \ref nvmlSystemGetProcessName - */ -nvmlReturn_t DECLDIR nvmlDeviceGetGraphicsRunningProcesses(nvmlDevice_t device, unsigned int *infoCount, nvmlProcessInfo_t *infos); - -/** - * Check if the GPU devices are on the same physical board. - * - * For all fully supported products. - * - * @param device1 The first GPU device - * @param device2 The second GPU device - * @param onSameBoard Reference in which to return the status. - * Non-zero indicates that the GPUs are on the same board. - * - * @return - * - \ref NVML_SUCCESS if \a onSameBoard has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a dev1 or \a dev2 are invalid or \a onSameBoard is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if this check is not supported by the device - * - \ref NVML_ERROR_GPU_IS_LOST if the either GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceOnSameBoard(nvmlDevice_t device1, nvmlDevice_t device2, int *onSameBoard); - -/** - * Retrieves the root/admin permissions on the target API. See \a nvmlRestrictedAPI_t for the list of supported APIs. - * If an API is restricted only root users can call that API. See \a nvmlDeviceSetAPIRestriction to change current permissions. - * - * For all fully supported products. - * - * @param device The identifier of the target device - * @param apiType Target API type for this operation - * @param isRestricted Reference in which to return the current restriction - * NVML_FEATURE_ENABLED indicates that the API is root-only - * NVML_FEATURE_DISABLED indicates that the API is accessible to all users - * - * @return - * - \ref NVML_SUCCESS if \a isRestricted has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a apiType incorrect or \a isRestricted is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device or the device does not support - * the feature that is being queried (E.G. Enabling/disabling Auto Boosted clocks is - * not supported by the device) - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlRestrictedAPI_t - */ -nvmlReturn_t DECLDIR nvmlDeviceGetAPIRestriction(nvmlDevice_t device, nvmlRestrictedAPI_t apiType, nvmlEnableState_t *isRestricted); - -/** - * Gets recent samples for the GPU. - * - * For Kepler &tm; or newer fully supported devices. - * - * Based on type, this method can be used to fetch the power, utilization or clock samples maintained in the buffer by - * the driver. - * - * Power, Utilization and Clock samples are returned as type "unsigned int" for the union nvmlValue_t. - * - * To get the size of samples that user needs to allocate, the method is invoked with samples set to NULL. - * The returned samplesCount will provide the number of samples that can be queried. The user needs to - * allocate the buffer with size as samplesCount * sizeof(nvmlSample_t). - * - * lastSeenTimeStamp represents CPU timestamp in microseconds. Set it to 0 to fetch all the samples maintained by the - * underlying buffer. Set lastSeenTimeStamp to one of the timeStamps retrieved from the date of the previous query - * to get more recent samples. - * - * This method fetches the number of entries which can be accommodated in the provided samples array, and the - * reference samplesCount is updated to indicate how many samples were actually retrieved. The advantage of using this - * method for samples in contrast to polling via existing methods is to get get higher frequency data at lower polling cost. - * - * @param device The identifier for the target device - * @param type Type of sampling event - * @param lastSeenTimeStamp Return only samples with timestamp greater than lastSeenTimeStamp. - * @param sampleValType Output parameter to represent the type of sample value as described in nvmlSampleVal_t - * @param sampleCount Reference to provide the number of elements which can be queried in samples array - * @param samples Reference in which samples are returned - - * @return - * - \ref NVML_SUCCESS if samples are successfully retrieved - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a samplesCount is NULL or - * reference to \a sampleCount is 0 for non null \a samples - * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_NOT_FOUND if sample entries are not found - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetSamples(nvmlDevice_t device, nvmlSamplingType_t type, unsigned long long lastSeenTimeStamp, - nvmlValueType_t *sampleValType, unsigned int *sampleCount, nvmlSample_t *samples); - -/** - * Gets Total, Available and Used size of BAR1 memory. - * - * BAR1 is used to map the FB (device memory) so that it can be directly accessed by the CPU or by 3rd party - * devices (peer-to-peer on the PCIE bus). - * - * For Kepler &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param bar1Memory Reference in which BAR1 memory - * information is returned. - * - * @return - * - \ref NVML_SUCCESS if BAR1 memory is successfully retrieved - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a bar1Memory is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - */ -nvmlReturn_t DECLDIR nvmlDeviceGetBAR1MemoryInfo(nvmlDevice_t device, nvmlBAR1Memory_t *bar1Memory); - - -/** - * Gets the duration of time during which the device was throttled (lower than requested clocks) due to power - * or thermal constraints. - * - * The method is important to users who are tying to understand if their GPUs throttle at any point during their applications. The - * difference in violation times at two different reference times gives the indication of GPU throttling event. - * - * Violation for thermal capping is not supported at this time. - * - * For Kepler &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param perfPolicyType Represents Performance policy which can trigger GPU throttling - * @param violTime Reference to which violation time related information is returned - * - * - * @return - * - \ref NVML_SUCCESS if violation time is successfully retrieved - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a perfPolicyType is invalid, or \a violTime is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - */ -nvmlReturn_t DECLDIR nvmlDeviceGetViolationStatus(nvmlDevice_t device, nvmlPerfPolicyType_t perfPolicyType, nvmlViolationTime_t *violTime); - -/** - * @} - */ - -/** @addtogroup nvmlAccountingStats - * @{ - */ - -/** - * Queries the state of per process accounting mode. - * - * For Kepler &tm; or newer fully supported devices. - * - * See \ref nvmlDeviceGetAccountingStats for more details. - * See \ref nvmlDeviceSetAccountingMode - * - * @param device The identifier of the target device - * @param mode Reference in which to return the current accounting mode - * - * @return - * - \ref NVML_SUCCESS if the mode has been successfully retrieved - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a mode are NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetAccountingMode(nvmlDevice_t device, nvmlEnableState_t *mode); - -/** - * Queries process's accounting stats. - * - * For Kepler &tm; or newer fully supported devices. - * - * Accounting stats capture GPU utilization and other statistics across the lifetime of a process. - * Accounting stats can be queried during life time of the process and after its termination. - * The time field in \ref nvmlAccountingStats_t is reported as 0 during the lifetime of the process and - * updated to actual running time after its termination. - * Accounting stats are kept in a circular buffer, newly created processes overwrite information about old - * processes. - * - * See \ref nvmlAccountingStats_t for description of each returned metric. - * List of processes that can be queried can be retrieved from \ref nvmlDeviceGetAccountingPids. - * - * @note Accounting Mode needs to be on. See \ref nvmlDeviceGetAccountingMode. - * @note Only compute and graphics applications stats can be queried. Monitoring applications stats can't be - * queried since they don't contribute to GPU utilization. - * @note In case of pid collision stats of only the latest process (that terminated last) will be reported - * - * @warning On Kepler devices per process statistics are accurate only if there's one process running on a GPU. - * - * @param device The identifier of the target device - * @param pid Process Id of the target process to query stats for - * @param stats Reference in which to return the process's accounting stats - * - * @return - * - \ref NVML_SUCCESS if stats have been successfully retrieved - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a stats are NULL - * - \ref NVML_ERROR_NOT_FOUND if process stats were not found - * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature or accounting mode is disabled - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlDeviceGetAccountingBufferSize - */ -nvmlReturn_t DECLDIR nvmlDeviceGetAccountingStats(nvmlDevice_t device, unsigned int pid, nvmlAccountingStats_t *stats); - -/** - * Queries list of processes that can be queried for accounting stats. The list of processes returned - * can be in running or terminated state. - * - * For Kepler &tm; or newer fully supported devices. - * - * To just query the number of processes ready to be queried, call this function with *count = 0 and - * pids=NULL. The return code will be NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if list is empty. - * - * For more details see \ref nvmlDeviceGetAccountingStats. - * - * @note In case of PID collision some processes might not be accessible before the circular buffer is full. - * - * @param device The identifier of the target device - * @param count Reference in which to provide the \a pids array size, and - * to return the number of elements ready to be queried - * @param pids Reference in which to return list of process ids - * - * @return - * - \ref NVML_SUCCESS if pids were successfully retrieved - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a count is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature or accounting mode is disabled - * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a count is too small (\a count is set to - * expected value) - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlDeviceGetAccountingBufferSize - */ -nvmlReturn_t DECLDIR nvmlDeviceGetAccountingPids(nvmlDevice_t device, unsigned int *count, unsigned int *pids); - -/** - * Returns the number of processes that the circular buffer with accounting pids can hold. - * - * For Kepler &tm; or newer fully supported devices. - * - * This is the maximum number of processes that accounting information will be stored for before information - * about oldest processes will get overwritten by information about new processes. - * - * @param device The identifier of the target device - * @param bufferSize Reference in which to provide the size (in number of elements) - * of the circular buffer for accounting stats. - * - * @return - * - \ref NVML_SUCCESS if buffer size was successfully retrieved - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a bufferSize is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature or accounting mode is disabled - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlDeviceGetAccountingStats - * @see nvmlDeviceGetAccountingPids - */ -nvmlReturn_t DECLDIR nvmlDeviceGetAccountingBufferSize(nvmlDevice_t device, unsigned int *bufferSize); - -/** @} */ - -/** @addtogroup nvmlDeviceQueries - * @{ - */ - -/** - * Returns the list of retired pages by source, including pages that are pending retirement - * The address information provided from this API is the hardware address of the page that was retired. Note - * that this does not match the virtual address used in CUDA, but will match the address information in XID 63 - * - * For Kepler &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param cause Filter page addresses by cause of retirement - * @param pageCount Reference in which to provide the \a addresses buffer size, and - * to return the number of retired pages that match \a cause - * Set to 0 to query the size without allocating an \a addresses buffer - * @param addresses Buffer to write the page addresses into - * - * @return - * - \ref NVML_SUCCESS if \a pageCount was populated and \a addresses was filled - * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a pageCount indicates the buffer is not large enough to store all the - * matching page addresses. \a pageCount is set to the needed size. - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a pageCount is NULL, \a cause is invalid, or - * \a addresses is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetRetiredPages(nvmlDevice_t device, nvmlPageRetirementCause_t cause, - unsigned int *pageCount, unsigned long long *addresses); - -/** - * Check if any pages are pending retirement and need a reboot to fully retire. - * - * For Kepler &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param isPending Reference in which to return the pending status - * - * @return - * - \ref NVML_SUCCESS if \a isPending was populated - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a isPending is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetRetiredPagesPendingStatus(nvmlDevice_t device, nvmlEnableState_t *isPending); - -/** @} */ - -/***************************************************************************************************/ -/** @defgroup nvmlUnitCommands Unit Commands - * This chapter describes NVML operations that change the state of the unit. For S-class products. - * Each of these requires root/admin access. Non-admin users will see an NVML_ERROR_NO_PERMISSION - * error code when invoking any of these methods. - * @{ - */ -/***************************************************************************************************/ - -/** - * Set the LED state for the unit. The LED can be either green (0) or amber (1). - * - * For S-class products. - * Requires root/admin permissions. - * - * This operation takes effect immediately. - * - * - * Current S-Class products don't provide unique LEDs for each unit. As such, both front - * and back LEDs will be toggled in unison regardless of which unit is specified with this command. - * - * See \ref nvmlLedColor_t for available colors. - * - * @param unit The identifier of the target unit - * @param color The target LED color - * - * @return - * - \ref NVML_SUCCESS if the LED color has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unit or \a color is invalid - * - \ref NVML_ERROR_NOT_SUPPORTED if this is not an S-class product - * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlUnitGetLedState() - */ -nvmlReturn_t DECLDIR nvmlUnitSetLedState(nvmlUnit_t unit, nvmlLedColor_t color); - -/** @} */ - -/***************************************************************************************************/ -/** @defgroup nvmlDeviceCommands Device Commands - * This chapter describes NVML operations that change the state of the device. - * Each of these requires root/admin access. Non-admin users will see an NVML_ERROR_NO_PERMISSION - * error code when invoking any of these methods. - * @{ - */ -/***************************************************************************************************/ - -/** - * Set the persistence mode for the device. - * - * For all products. - * For Linux only. - * Requires root/admin permissions. - * - * The persistence mode determines whether the GPU driver software is torn down after the last client - * exits. - * - * This operation takes effect immediately. It is not persistent across reboots. After each reboot the - * persistence mode is reset to "Disabled". - * - * See \ref nvmlEnableState_t for available modes. - * - * @param device The identifier of the target device - * @param mode The target persistence mode - * - * @return - * - \ref NVML_SUCCESS if the persistence mode was set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a mode is invalid - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlDeviceGetPersistenceMode() - */ -nvmlReturn_t DECLDIR nvmlDeviceSetPersistenceMode(nvmlDevice_t device, nvmlEnableState_t mode); - -/** - * Set the compute mode for the device. - * - * For all products. - * Requires root/admin permissions. - * - * The compute mode determines whether a GPU can be used for compute operations and whether it can - * be shared across contexts. - * - * This operation takes effect immediately. Under Linux it is not persistent across reboots and - * always resets to "Default". Under windows it is persistent. - * - * Under windows compute mode may only be set to DEFAULT when running in WDDM - * - * See \ref nvmlComputeMode_t for details on available compute modes. - * - * @param device The identifier of the target device - * @param mode The target compute mode - * - * @return - * - \ref NVML_SUCCESS if the compute mode was set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a mode is invalid - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlDeviceGetComputeMode() - */ -nvmlReturn_t DECLDIR nvmlDeviceSetComputeMode(nvmlDevice_t device, nvmlComputeMode_t mode); - -/** - * Set the ECC mode for the device. - * - * For Kepler &tm; or newer fully supported devices. - * Only applicable to devices with ECC. - * Requires \a NVML_INFOROM_ECC version 1.0 or higher. - * Requires root/admin permissions. - * - * The ECC mode determines whether the GPU enables its ECC support. - * - * This operation takes effect after the next reboot. - * - * See \ref nvmlEnableState_t for details on available modes. - * - * @param device The identifier of the target device - * @param ecc The target ECC mode - * - * @return - * - \ref NVML_SUCCESS if the ECC mode was set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a ecc is invalid - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlDeviceGetEccMode() - */ -nvmlReturn_t DECLDIR nvmlDeviceSetEccMode(nvmlDevice_t device, nvmlEnableState_t ecc); - -/** - * Clear the ECC error and other memory error counts for the device. - * - * For Kepler &tm; or newer fully supported devices. - * Only applicable to devices with ECC. - * Requires \a NVML_INFOROM_ECC version 2.0 or higher to clear aggregate location-based ECC counts. - * Requires \a NVML_INFOROM_ECC version 1.0 or higher to clear all other ECC counts. - * Requires root/admin permissions. - * Requires ECC Mode to be enabled. - * - * Sets all of the specified ECC counters to 0, including both detailed and total counts. - * - * This operation takes effect immediately. - * - * See \ref nvmlMemoryErrorType_t for details on available counter types. - * - * @param device The identifier of the target device - * @param counterType Flag that indicates which type of errors should be cleared. - * - * @return - * - \ref NVML_SUCCESS if the error counts were cleared - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a counterType is invalid - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see - * - nvmlDeviceGetDetailedEccErrors() - * - nvmlDeviceGetTotalEccErrors() - */ -nvmlReturn_t DECLDIR nvmlDeviceClearEccErrorCounts(nvmlDevice_t device, nvmlEccCounterType_t counterType); - -/** - * Set the driver model for the device. - * - * For Fermi &tm; or newer fully supported devices. - * For windows only. - * Requires root/admin permissions. - * - * On Windows platforms the device driver can run in either WDDM or WDM (TCC) mode. If a display is attached - * to the device it must run in WDDM mode. - * - * It is possible to force the change to WDM (TCC) while the display is still attached with a force flag (nvmlFlagForce). - * This should only be done if the host is subsequently powered down and the display is detached from the device - * before the next reboot. - * - * This operation takes effect after the next reboot. - * - * Windows driver model may only be set to WDDM when running in DEFAULT compute mode. - * - * Change driver model to WDDM is not supported when GPU doesn't support graphics acceleration or - * will not support it after reboot. See \ref nvmlDeviceSetGpuOperationMode. - * - * See \ref nvmlDriverModel_t for details on available driver models. - * See \ref nvmlFlagDefault and \ref nvmlFlagForce - * - * @param device The identifier of the target device - * @param driverModel The target driver model - * @param flags Flags that change the default behavior - * - * @return - * - \ref NVML_SUCCESS if the driver model has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a driverModel is invalid - * - \ref NVML_ERROR_NOT_SUPPORTED if the platform is not windows or the device does not support this feature - * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlDeviceGetDriverModel() - */ -nvmlReturn_t DECLDIR nvmlDeviceSetDriverModel(nvmlDevice_t device, nvmlDriverModel_t driverModel, unsigned int flags); - -/** - * Set clocks that applications will lock to. - * - * Sets the clocks that compute and graphics applications will be running at. - * e.g. CUDA driver requests these clocks during context creation which means this property - * defines clocks at which CUDA applications will be running unless some overspec event - * occurs (e.g. over power, over thermal or external HW brake). - * - * Can be used as a setting to request constant performance. - * - * On Pascal and newer hardware, this will automatically disable automatic boosting of clocks. - * - * On K80 and newer Kepler and Maxwell GPUs, users desiring fixed performance should also call - * \ref nvmlDeviceSetAutoBoostedClocksEnabled to prevent clocks from automatically boosting - * above the clock value being set. - * - * For Kepler &tm; or newer non-GeForce fully supported devices and Maxwell or newer GeForce devices. - * Requires root/admin permissions. - * - * See \ref nvmlDeviceGetSupportedMemoryClocks and \ref nvmlDeviceGetSupportedGraphicsClocks - * for details on how to list available clocks combinations. - * - * After system reboot or driver reload applications clocks go back to their default value. - * See \ref nvmlDeviceResetApplicationsClocks. - * - * @param device The identifier of the target device - * @param memClockMHz Requested memory clock in MHz - * @param graphicsClockMHz Requested graphics clock in MHz - * - * @return - * - \ref NVML_SUCCESS if new settings were successfully set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a memClockMHz and \a graphicsClockMHz - * is not a valid clock combination - * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation - * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceSetApplicationsClocks(nvmlDevice_t device, unsigned int memClockMHz, unsigned int graphicsClockMHz); - -/** - * Set new power limit of this device. - * - * For Kepler &tm; or newer fully supported devices. - * Requires root/admin permissions. - * - * See \ref nvmlDeviceGetPowerManagementLimitConstraints to check the allowed ranges of values. - * - * \note Limit is not persistent across reboots or driver unloads. - * Enable persistent mode to prevent driver from unloading when no application is using the device. - * - * @param device The identifier of the target device - * @param limit Power management limit in milliwatts to set - * - * @return - * - \ref NVML_SUCCESS if \a limit has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a defaultLimit is out of range - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlDeviceGetPowerManagementLimitConstraints - * @see nvmlDeviceGetPowerManagementDefaultLimit - */ -nvmlReturn_t DECLDIR nvmlDeviceSetPowerManagementLimit(nvmlDevice_t device, unsigned int limit); - -/** - * Sets new GOM. See \a nvmlGpuOperationMode_t for details. - * - * For GK110 M-class and X-class Tesla &tm; products from the Kepler family. - * Modes \ref NVML_GOM_LOW_DP and \ref NVML_GOM_ALL_ON are supported on fully supported GeForce products. - * Not supported on Quadro ® and Tesla &tm; C-class products. - * Requires root/admin permissions. - * - * Changing GOMs requires a reboot. - * The reboot requirement might be removed in the future. - * - * Compute only GOMs don't support graphics acceleration. Under windows switching to these GOMs when - * pending driver model is WDDM is not supported. See \ref nvmlDeviceSetDriverModel. - * - * @param device The identifier of the target device - * @param mode Target GOM - * - * @return - * - \ref NVML_SUCCESS if \a mode has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a mode incorrect - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support GOM or specific mode - * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlGpuOperationMode_t - * @see nvmlDeviceGetGpuOperationMode - */ -nvmlReturn_t DECLDIR nvmlDeviceSetGpuOperationMode(nvmlDevice_t device, nvmlGpuOperationMode_t mode); - -/** - * Changes the root/admin restructions on certain APIs. See \a nvmlRestrictedAPI_t for the list of supported APIs. - * This method can be used by a root/admin user to give non-root/admin access to certain otherwise-restricted APIs. - * The new setting lasts for the lifetime of the NVIDIA driver; it is not persistent. See \a nvmlDeviceGetAPIRestriction - * to query the current restriction settings. - * - * For Kepler &tm; or newer fully supported devices. - * Requires root/admin permissions. - * - * @param device The identifier of the target device - * @param apiType Target API type for this operation - * @param isRestricted The target restriction - * - * @return - * - \ref NVML_SUCCESS if \a isRestricted has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a apiType incorrect - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support changing API restrictions or the device does not support - * the feature that api restrictions are being set for (E.G. Enabling/disabling auto - * boosted clocks is not supported by the device) - * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlRestrictedAPI_t - */ -nvmlReturn_t DECLDIR nvmlDeviceSetAPIRestriction(nvmlDevice_t device, nvmlRestrictedAPI_t apiType, nvmlEnableState_t isRestricted); - -/** - * @} - */ - -/** @addtogroup nvmlAccountingStats - * @{ - */ - -/** - * Enables or disables per process accounting. - * - * For Kepler &tm; or newer fully supported devices. - * Requires root/admin permissions. - * - * @note This setting is not persistent and will default to disabled after driver unloads. - * Enable persistence mode to be sure the setting doesn't switch off to disabled. - * - * @note Enabling accounting mode has no negative impact on the GPU performance. - * - * @note Disabling accounting clears all accounting pids information. - * - * See \ref nvmlDeviceGetAccountingMode - * See \ref nvmlDeviceGetAccountingStats - * See \ref nvmlDeviceClearAccountingPids - * - * @param device The identifier of the target device - * @param mode The target accounting mode - * - * @return - * - \ref NVML_SUCCESS if the new mode has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a mode are invalid - * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature - * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceSetAccountingMode(nvmlDevice_t device, nvmlEnableState_t mode); - -/** - * Clears accounting information about all processes that have already terminated. - * - * For Kepler &tm; or newer fully supported devices. - * Requires root/admin permissions. - * - * See \ref nvmlDeviceGetAccountingMode - * See \ref nvmlDeviceGetAccountingStats - * See \ref nvmlDeviceSetAccountingMode - * - * @param device The identifier of the target device - * - * @return - * - \ref NVML_SUCCESS if accounting information has been cleared - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device are invalid - * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature - * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceClearAccountingPids(nvmlDevice_t device); - -/** @} */ - -/***************************************************************************************************/ -/** @defgroup NvLink NvLink Methods - * This chapter describes methods that NVML can perform on NVLINK enabled devices. - * @{ - */ -/***************************************************************************************************/ - -/** - * Retrieves the state of the device's NvLink for the link specified - * - * For Pascal &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param link Specifies the NvLink link to be queried - * @param isActive \a nvmlEnableState_t where NVML_FEATURE_ENABLED indicates that - * the link is active and NVML_FEATURE_DISABLED indicates it - * is inactive - * - * @return - * - \ref NVML_SUCCESS if \a isActive has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a link is invalid or \a isActive is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkState(nvmlDevice_t device, unsigned int link, nvmlEnableState_t *isActive); - -/** - * Retrieves the version of the device's NvLink for the link specified - * - * For Pascal &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param link Specifies the NvLink link to be queried - * @param version Requested NvLink version - * - * @return - * - \ref NVML_SUCCESS if \a version has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a link is invalid or \a version is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkVersion(nvmlDevice_t device, unsigned int link, unsigned int *version); - -/** - * Retrieves the requested capability from the device's NvLink for the link specified - * Please refer to the \a nvmlNvLinkCapability_t structure for the specific caps that can be queried - * The return value should be treated as a boolean. - * - * For Pascal &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param link Specifies the NvLink link to be queried - * @param capability Specifies the \a nvmlNvLinkCapability_t to be queried - * @param capResult A boolean for the queried capability indicating that feature is available - * - * @return - * - \ref NVML_SUCCESS if \a capResult has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a link, or \a capability is invalid or \a capResult is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkCapability(nvmlDevice_t device, unsigned int link, - nvmlNvLinkCapability_t capability, unsigned int *capResult); - -/** - * Retrieves the PCI information for the remote node on a NvLink link - * Note: pciSubSystemId is not filled in this function and is indeterminate - * - * For Pascal &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param link Specifies the NvLink link to be queried - * @param pci \a nvmlPciInfo_t of the remote node for the specified link - * - * @return - * - \ref NVML_SUCCESS if \a pci has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a link is invalid or \a pci is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkRemotePciInfo(nvmlDevice_t device, unsigned int link, nvmlPciInfo_t *pci); - -/** - * Retrieves the specified error counter value - * Please refer to \a nvmlNvLinkErrorCounter_t for error counters that are available - * - * For Pascal &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param link Specifies the NvLink link to be queried - * @param counter Specifies the NvLink counter to be queried - * @param counterValue Returned counter value - * - * @return - * - \ref NVML_SUCCESS if \a counter has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a link, or \a counter is invalid or \a counterValue is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkErrorCounter(nvmlDevice_t device, unsigned int link, - nvmlNvLinkErrorCounter_t counter, unsigned long long *counterValue); - -/** - * Resets all error counters to zero - * Please refer to \a nvmlNvLinkErrorCounter_t for the list of error counters that are reset - * - * For Pascal &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param link Specifies the NvLink link to be queried - * - * @return - * - \ref NVML_SUCCESS if the reset is successful - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a link is invalid - * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceResetNvLinkErrorCounters(nvmlDevice_t device, unsigned int link); - -/** - * Set the NVLINK utilization counter control information for the specified counter, 0 or 1. - * Please refer to \a nvmlNvLinkUtilizationControl_t for the structure definition. Performs a reset - * of the counters if the reset parameter is non-zero. - * - * For Pascal &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param counter Specifies the counter that should be set (0 or 1). - * @param link Specifies the NvLink link to be queried - * @param control A reference to the \a nvmlNvLinkUtilizationControl_t to set - * @param reset Resets the counters on set if non-zero - * - * @return - * - \ref NVML_SUCCESS if the control has been set successfully - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a counter, \a link, or \a control is invalid - * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceSetNvLinkUtilizationControl(nvmlDevice_t device, unsigned int link, unsigned int counter, - nvmlNvLinkUtilizationControl_t *control, unsigned int reset); - -/** - * Get the NVLINK utilization counter control information for the specified counter, 0 or 1. - * Please refer to \a nvmlNvLinkUtilizationControl_t for the structure definition - * - * For Pascal &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param counter Specifies the counter that should be set (0 or 1). - * @param link Specifies the NvLink link to be queried - * @param control A reference to the \a nvmlNvLinkUtilizationControl_t to place information - * - * @return - * - \ref NVML_SUCCESS if the control has been set successfully - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a counter, \a link, or \a control is invalid - * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkUtilizationControl(nvmlDevice_t device, unsigned int link, unsigned int counter, - nvmlNvLinkUtilizationControl_t *control); - - -/** - * Retrieve the NVLINK utilization counter based on the current control for a specified counter. - * In general it is good practice to use \a nvmlDeviceSetNvLinkUtilizationControl - * before reading the utilization counters as they have no default state - * - * For Pascal &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param link Specifies the NvLink link to be queried - * @param counter Specifies the counter that should be read (0 or 1). - * @param rxcounter Receive counter return value - * @param txcounter Transmit counter return value - * - * @return - * - \ref NVML_SUCCESS if \a rxcounter and \a txcounter have been successfully set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a counter, or \a link is invalid or \a rxcounter or \a txcounter are NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkUtilizationCounter(nvmlDevice_t device, unsigned int link, unsigned int counter, - unsigned long long *rxcounter, unsigned long long *txcounter); - -/** - * Freeze the NVLINK utilization counters - * Both the receive and transmit counters are operated on by this function - * - * For Pascal &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param link Specifies the NvLink link to be queried - * @param counter Specifies the counter that should be frozen (0 or 1). - * @param freeze NVML_FEATURE_ENABLED = freeze the receive and transmit counters - * NVML_FEATURE_DISABLED = unfreeze the receive and transmit counters - * - * @return - * - \ref NVML_SUCCESS if counters were successfully frozen or unfrozen - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a link, \a counter, or \a freeze is invalid - * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceFreezeNvLinkUtilizationCounter (nvmlDevice_t device, unsigned int link, - unsigned int counter, nvmlEnableState_t freeze); - -/** - * Reset the NVLINK utilization counters - * Both the receive and transmit counters are operated on by this function - * - * For Pascal &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param link Specifies the NvLink link to be reset - * @param counter Specifies the counter that should be reset (0 or 1) - * - * @return - * - \ref NVML_SUCCESS if counters were successfully reset - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a link, or \a counter is invalid - * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceResetNvLinkUtilizationCounter (nvmlDevice_t device, unsigned int link, unsigned int counter); - -/** @} */ - -/***************************************************************************************************/ -/** @defgroup nvmlEvents Event Handling Methods - * This chapter describes methods that NVML can perform against each device to register and wait for - * some event to occur. - * @{ - */ -/***************************************************************************************************/ - -/** - * Create an empty set of events. - * Event set should be freed by \ref nvmlEventSetFree - * - * For Fermi &tm; or newer fully supported devices. - * @param set Reference in which to return the event handle - * - * @return - * - \ref NVML_SUCCESS if the event has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a set is NULL - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlEventSetFree - */ -nvmlReturn_t DECLDIR nvmlEventSetCreate(nvmlEventSet_t *set); - -/** - * Starts recording of events on a specified devices and add the events to specified \ref nvmlEventSet_t - * - * For Fermi &tm; or newer fully supported devices. - * Ecc events are available only on ECC enabled devices (see \ref nvmlDeviceGetTotalEccErrors) - * Power capping events are available only on Power Management enabled devices (see \ref nvmlDeviceGetPowerManagementMode) - * - * For Linux only. - * - * \b IMPORTANT: Operations on \a set are not thread safe - * - * This call starts recording of events on specific device. - * All events that occurred before this call are not recorded. - * Checking if some event occurred can be done with \ref nvmlEventSetWait - * - * If function reports NVML_ERROR_UNKNOWN, event set is in undefined state and should be freed. - * If function reports NVML_ERROR_NOT_SUPPORTED, event set can still be used. None of the requested eventTypes - * are registered in that case. - * - * @param device The identifier of the target device - * @param eventTypes Bitmask of \ref nvmlEventType to record - * @param set Set to which add new event types - * - * @return - * - \ref NVML_SUCCESS if the event has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a eventTypes is invalid or \a set is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the platform does not support this feature or some of requested event types - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlEventType - * @see nvmlDeviceGetSupportedEventTypes - * @see nvmlEventSetWait - * @see nvmlEventSetFree - */ -nvmlReturn_t DECLDIR nvmlDeviceRegisterEvents(nvmlDevice_t device, unsigned long long eventTypes, nvmlEventSet_t set); - -/** - * Returns information about events supported on device - * - * For Fermi &tm; or newer fully supported devices. - * - * Events are not supported on Windows. So this function returns an empty mask in \a eventTypes on Windows. - * - * @param device The identifier of the target device - * @param eventTypes Reference in which to return bitmask of supported events - * - * @return - * - \ref NVML_SUCCESS if the eventTypes has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a eventType is NULL - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlEventType - * @see nvmlDeviceRegisterEvents - */ -nvmlReturn_t DECLDIR nvmlDeviceGetSupportedEventTypes(nvmlDevice_t device, unsigned long long *eventTypes); - -/** - * Waits on events and delivers events - * - * For Fermi &tm; or newer fully supported devices. - * - * If some events are ready to be delivered at the time of the call, function returns immediately. - * If there are no events ready to be delivered, function sleeps till event arrives - * but not longer than specified timeout. This function in certain conditions can return before - * specified timeout passes (e.g. when interrupt arrives) - * - * In case of xid error, the function returns the most recent xid error type seen by the system. If there are multiple - * xid errors generated before nvmlEventSetWait is invoked then the last seen xid error type is returned for all - * xid error events. - * - * @param set Reference to set of events to wait on - * @param data Reference in which to return event data - * @param timeoutms Maximum amount of wait time in milliseconds for registered event - * - * @return - * - \ref NVML_SUCCESS if the data has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a data is NULL - * - \ref NVML_ERROR_TIMEOUT if no event arrived in specified timeout or interrupt arrived - * - \ref NVML_ERROR_GPU_IS_LOST if a GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlEventType - * @see nvmlDeviceRegisterEvents - */ -nvmlReturn_t DECLDIR nvmlEventSetWait(nvmlEventSet_t set, nvmlEventData_t * data, unsigned int timeoutms); - -/** - * Releases events in the set - * - * For Fermi &tm; or newer fully supported devices. - * - * @param set Reference to events to be released - * - * @return - * - \ref NVML_SUCCESS if the event has been successfully released - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - * - * @see nvmlDeviceRegisterEvents - */ -nvmlReturn_t DECLDIR nvmlEventSetFree(nvmlEventSet_t set); - -/** @} */ - -/***************************************************************************************************/ -/** @defgroup nvmlZPI Drain states - * This chapter describes methods that NVML can perform against each device to control their drain state - * and recognition by NVML and NVIDIA kernel driver. These methods can be used with out-of-band tools to - * power on/off GPUs, enable robust reset scenarios, etc. - * @{ - */ -/***************************************************************************************************/ - -/** - * Modify the drain state of a GPU. This method forces a GPU to no longer accept new incoming requests. - * Any new NVML process will no longer see this GPU. Persistence mode for this GPU must be turned off before - * this call is made. - * Must be called as administrator. - * For Linux only. - * - * For Pascal &tm; or newer fully supported devices. - * Some Kepler devices supported. - * - * @param pciInfo The PCI address of the GPU drain state to be modified - * @param newState The drain state that should be entered, see \ref nvmlEnableState_t - * - * @return - * - \ref NVML_SUCCESS if counters were successfully reset - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a nvmlIndex or \a newState is invalid - * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature - * - \ref NVML_ERROR_NO_PERMISSION if the calling process has insufficient permissions to perform operation - * - \ref NVML_ERROR_IN_USE if the device has persistence mode turned on - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceModifyDrainState (nvmlPciInfo_t *pciInfo, nvmlEnableState_t newState); - -/** - * Query the drain state of a GPU. This method is used to check if a GPU is in a currently draining - * state. - * For Linux only. - * - * For Pascal &tm; or newer fully supported devices. - * Some Kepler devices supported. - * - * @param pciInfo The PCI address of the GPU drain state to be queried - * @param currentState The current drain state for this GPU, see \ref nvmlEnableState_t - * - * @return - * - \ref NVML_SUCCESS if counters were successfully reset - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a nvmlIndex or \a currentState is invalid - * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceQueryDrainState (nvmlPciInfo_t *pciInfo, nvmlEnableState_t *currentState); - -/** - * This method will remove the specified GPU from the view of both NVML and the NVIDIA kernel driver - * as long as no other processes are attached. If other processes are attached, this call will return - * NVML_ERROR_IN_USE and the GPU will be returned to its original "draining" state. Note: the - * only situation where a process can still be attached after nvmlDeviceModifyDrainState() is called - * to initiate the draining state is if that process was using, and is still using, a GPU before the - * call was made. Also note, persistence mode counts as an attachment to the GPU thus it must be disabled - * prior to this call. - * - * For long-running NVML processes please note that this will change the enumeration of current GPUs. - * For example, if there are four GPUs present and GPU1 is removed, the new enumeration will be 0-2. - * Also, device handles after the removed GPU will not be valid and must be re-established. - * Must be run as administrator. - * For Linux only. - * - * For Pascal &tm; or newer fully supported devices. - * Some Kepler devices supported. - * - * @param pciInfo The PCI address of the GPU to be removed - * - * @return - * - \ref NVML_SUCCESS if counters were successfully reset - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a nvmlIndex is invalid - * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature - * - \ref NVML_ERROR_IN_USE if the device is still in use and cannot be removed - */ -nvmlReturn_t DECLDIR nvmlDeviceRemoveGpu (nvmlPciInfo_t *pciInfo); - -/** - * Request the OS and the NVIDIA kernel driver to rediscover a portion of the PCI subsystem looking for GPUs that - * were previously removed. The portion of the PCI tree can be narrowed by specifying a domain, bus, and device. - * If all are zeroes then the entire PCI tree will be searched. Please note that for long-running NVML processes - * the enumeration will change based on how many GPUs are discovered and where they are inserted in bus order. - * - * In addition, all newly discovered GPUs will be initialized and their ECC scrubbed which may take several seconds - * per GPU. Also, all device handles are no longer guaranteed to be valid post discovery. - * - * Must be run as administrator. - * For Linux only. - * - * For Pascal &tm; or newer fully supported devices. - * Some Kepler devices supported. - * - * @param pciInfo The PCI tree to be searched. Only the domain, bus, and device - * fields are used in this call. - * - * @return - * - \ref NVML_SUCCESS if counters were successfully reset - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a pciInfo is invalid - * - \ref NVML_ERROR_NOT_SUPPORTED if the operating system does not support this feature - * - \ref NVML_ERROR_OPERATING_SYSTEM if the operating system is denying this feature - * - \ref NVML_ERROR_NO_PERMISSION if the calling process has insufficient permissions to perform operation - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceDiscoverGpus (nvmlPciInfo_t *pciInfo); - -/** @} */ - -/***************************************************************************************************/ -/** @defgroup nvmlFieldValueQueries Field Value Queries - * This chapter describes NVML operations that are associated with retrieving Field Values from NVML - * @{ - */ -/***************************************************************************************************/ - -/** - * Request values for a list of fields for a device. This API allows multiple fields to be queried at once. - * If any of the underlying fieldIds are populated by the same driver call, the results for those field IDs - * will be populated from a single call rather than making a driver call for each fieldId. - * - * @param device The device handle of the GPU to request field values for - * @param valuesCount Number of entries in values that should be retrieved - * @param values Array of \a valuesCount structures to hold field values. - * Each value's fieldId must be populated prior to this call - * - * @return - * - \ref NVML_SUCCESS if any values in \a values were populated. Note that you must - * check the nvmlReturn field of each value for each individual - * status - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a values is NULL - */ -nvmlReturn_t DECLDIR nvmlDeviceGetFieldValues(nvmlDevice_t device, int valuesCount, nvmlFieldValue_t *values); - - -/** @} */ - -/***************************************************************************************************/ -/** @defgroup nvmlGridQueries Grid Queries - * This chapter describes NVML operations that are associated with NVIDIA GRID products. - * @{ - */ -/***************************************************************************************************/ - -/** - * This method is used to get the virtualization mode corresponding to the GPU. - * - * For Kepler &tm; or newer fully supported devices. - * - * @param device Identifier of the target device - * @param pVirtualMode Reference to virtualization mode. One of NVML_GPU_VIRTUALIZATION_? - * - * @return - * - \ref NVML_SUCCESS if \a pVirtualMode is fetched - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a pVirtualMode is NULL - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetVirtualizationMode(nvmlDevice_t device, nvmlGpuVirtualizationMode_t *pVirtualMode); - -/** @} */ - -/***************************************************************************************************/ -/** @defgroup nvmlGridCommands Grid Commands - * This chapter describes NVML operations that are associated with NVIDIA GRID products. - * @{ - */ -/***************************************************************************************************/ - -/** - * This method is used to set the virtualization mode corresponding to the GPU. - * - * For Kepler &tm; or newer fully supported devices. - * - * @param device Identifier of the target device - * @param virtualMode virtualization mode. One of NVML_GPU_VIRTUALIZATION_? - * - * @return - * - \ref NVML_SUCCESS if \a pVirtualMode is set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a pVirtualMode is NULL - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_NOT_SUPPORTED if setting of virtualization mode is not supported. - * - \ref NVML_ERROR_NO_PERMISSION if setting of virtualization mode is not allowed for this client. - */ -nvmlReturn_t DECLDIR nvmlDeviceSetVirtualizationMode(nvmlDevice_t device, nvmlGpuVirtualizationMode_t virtualMode); - -/** @} */ - -/***************************************************************************************************/ -/** @defgroup nvmlVgpu vGPU Management - * @{ - * - * Set of APIs supporting GRID vGPU - */ -/***************************************************************************************************/ - -/** - * Retrieve the supported vGPU types on a physical GPU (device). - * - * An array of supported vGPU types for the physical GPU indicated by \a device is returned in the caller-supplied buffer - * pointed at by \a vgpuTypeIds. The element count of nvmlVgpuTypeId_t array is passed in \a vgpuCount, and \a vgpuCount - * is used to return the number of vGPU types written to the buffer. - * - * If the supplied buffer is not large enough to accomodate the vGPU type array, the function returns - * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlVgpuTypeId_t array required in \a vgpuCount. - * To query the number of vGPU types supported for the GPU, call this function with *vgpuCount = 0. - * The code will return NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if no vGPU types are supported. - * - * @param device The identifier of the target device - * @param vgpuCount Pointer to caller-supplied array size, and returns number of vGPU types - * @param vgpuTypeIds Pointer to caller-supplied array in which to return list of vGPU types - * - * @return - * - \ref NVML_SUCCESS successful completion - * - \ref NVML_ERROR_INSUFFICIENT_SIZE \a vgpuTypeIds buffer is too small, array element count is returned in \a vgpuCount - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuCount is NULL or \a device is invalid - * - \ref NVML_ERROR_NOT_SUPPORTED if vGPU is not supported by the device - * - \ref NVML_ERROR_VGPU_ECC_NOT_SUPPORTED if ECC is enabled on the device - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetSupportedVgpus(nvmlDevice_t device, unsigned int *vgpuCount, nvmlVgpuTypeId_t *vgpuTypeIds); - -/** - * Retrieve the currently creatable vGPU types on a physical GPU (device). - * - * An array of creatable vGPU types for the physical GPU indicated by \a device is returned in the caller-supplied buffer - * pointed at by \a vgpuTypeIds. The element count of nvmlVgpuTypeId_t array is passed in \a vgpuCount, and \a vgpuCount - * is used to return the number of vGPU types written to the buffer. - * - * The creatable vGPU types for a device may differ over time, as there may be restrictions on what type of vGPU types - * can concurrently run on a device. For example, if only one vGPU type is allowed at a time on a device, then the creatable - * list will be restricted to whatever vGPU type is already running on the device. - * - * If the supplied buffer is not large enough to accomodate the vGPU type array, the function returns - * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlVgpuTypeId_t array required in \a vgpuCount. - * To query the number of vGPU types createable for the GPU, call this function with *vgpuCount = 0. - * The code will return NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if no vGPU types are creatable. - * - * @param device The identifier of the target device - * @param vgpuCount Pointer to caller-supplied array size, and returns number of vGPU types - * @param vgpuTypeIds Pointer to caller-supplied array in which to return list of vGPU types - * - * @return - * - \ref NVML_SUCCESS successful completion - * - \ref NVML_ERROR_INSUFFICIENT_SIZE \a vgpuTypeIds buffer is too small, array element count is returned in \a vgpuCount - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuCount is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if vGPU is not supported by the device - * - \ref NVML_ERROR_VGPU_ECC_NOT_SUPPORTED if ECC is enabled on the device - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetCreatableVgpus(nvmlDevice_t device, unsigned int *vgpuCount, nvmlVgpuTypeId_t *vgpuTypeIds); - -/** - * Retrieve the class of a vGPU type. It will not exceed 64 characters in length (including the NUL terminator). - * See \ref nvmlConstants::NVML_DEVICE_NAME_BUFFER_SIZE. - * - * For Kepler &tm; or newer fully supported devices. - * - * @param vgpuTypeId Handle to vGPU type - * @param vgpuTypeClass Pointer to string array to return class in - * @param size Size of string - * - * @return - * - \ref NVML_SUCCESS successful completion - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a vgpuTypeClass is NULL - * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a size is too small - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlVgpuTypeGetClass(nvmlVgpuTypeId_t vgpuTypeId, char *vgpuTypeClass, unsigned int *size); - -/** - * Retrieve the vGPU type name. - * - * The name is an alphanumeric string that denotes a particular vGPU, e.g. GRID M60-2Q. It will not - * exceed 64 characters in length (including the NUL terminator). See \ref - * nvmlConstants::NVML_DEVICE_NAME_BUFFER_SIZE. - * - * For Kepler &tm; or newer fully supported devices. - * - * @param vgpuTypeId Handle to vGPU type - * @param vgpuTypeName Pointer to buffer to return name - * @param size Size of buffer - * - * @return - * - \ref NVML_SUCCESS successful completion - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a name is NULL - * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a size is too small - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlVgpuTypeGetName(nvmlVgpuTypeId_t vgpuTypeId, char *vgpuTypeName, unsigned int *size); - -/** - * Retrieve the device ID of a vGPU type. - * - * For Kepler &tm; or newer fully supported devices. - * - * @param vgpuTypeId Handle to vGPU type - * @param deviceID Device ID and vendor ID of the device contained in single 32 bit value - * @param subsystemID Subsytem ID and subsytem vendor ID of the device contained in single 32 bit value - * - * @return - * - \ref NVML_SUCCESS successful completion - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a deviceId or \a subsystemID are NULL - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlVgpuTypeGetDeviceID(nvmlVgpuTypeId_t vgpuTypeId, unsigned long long *deviceID, unsigned long long *subsystemID); - -/** - * Retrieve the vGPU framebuffer size in bytes. - * - * For Kepler &tm; or newer fully supported devices. - * - * @param vgpuTypeId Handle to vGPU type - * @param fbSize Pointer to framebuffer size in bytes - * - * @return - * - \ref NVML_SUCCESS successful completion - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a fbSize is NULL - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlVgpuTypeGetFramebufferSize(nvmlVgpuTypeId_t vgpuTypeId, unsigned long long *fbSize); - -/** - * Retrieve count of vGPU's supported display heads. - * - * For Kepler &tm; or newer fully supported devices. - * - * @param vgpuTypeId Handle to vGPU type - * @param numDisplayHeads Pointer to number of display heads - * - * @return - * - \ref NVML_SUCCESS successful completion - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a numDisplayHeads is NULL - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlVgpuTypeGetNumDisplayHeads(nvmlVgpuTypeId_t vgpuTypeId, unsigned int *numDisplayHeads); - -/** - * Retrieve vGPU display head's maximum supported resolution. - * - * For Kepler &tm; or newer fully supported devices. - * - * @param vgpuTypeId Handle to vGPU type - * @param displayIndex Zero-based index of display head - * @param xdim Pointer to maximum number of pixels in X dimension - * @param ydim Pointer to maximum number of pixels in Y dimension - * - * @return - * - \ref NVML_SUCCESS successful completion - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a xdim or \a ydim are NULL, or \a displayIndex - * is out of range. - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlVgpuTypeGetResolution(nvmlVgpuTypeId_t vgpuTypeId, unsigned int displayIndex, unsigned int *xdim, unsigned int *ydim); - -/** - * Retrieve license requirements for a vGPU type - * - * The license type and version required to run the specified vGPU type is returned as an alphanumeric string, in the form - * ",", for example "GRID-Virtual-PC,2.0". If a vGPU is runnable with* more than one type of license, - * the licenses are delimited by a semicolon, for example "GRID-Virtual-PC,2.0;GRID-Virtual-WS,2.0;GRID-Virtual-WS-Ext,2.0". - * - * The total length of the returned string will not exceed 128 characters, including the NUL terminator. - * See \ref nvmlVgpuConstants::NVML_GRID_LICENSE_BUFFER_SIZE. - * - * For Kepler &tm; or newer fully supported devices. - * - * @param vgpuTypeId Handle to vGPU type - * @param vgpuTypeLicenseString Pointer to buffer to return license info - * @param size Size of \a vgpuTypeLicenseString buffer - * - * @return - * - \ref NVML_SUCCESS successful completion - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a vgpuTypeLicenseString is NULL - * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a size is too small - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlVgpuTypeGetLicense(nvmlVgpuTypeId_t vgpuTypeId, char *vgpuTypeLicenseString, unsigned int size); - -/** - * Retrieve the static frame rate limit value of the vGPU type - * - * For Kepler &tm; or newer fully supported devices. - * - * @param vgpuTypeId Handle to vGPU type - * @param frameRateLimit Reference to return the frame rate limit value - * @return - * - \ref NVML_SUCCESS successful completion - * - \ref NVML_ERROR_NOT_SUPPORTED if frame rate limiter is turned off for the vGPU type - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a frameRateLimit is NULL - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlVgpuTypeGetFrameRateLimit(nvmlVgpuTypeId_t vgpuTypeId, unsigned int *frameRateLimit); - -/** - * Retrieve the maximum number of vGPU instances creatable on a device for given vGPU type - * - * For Kepler &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param vgpuTypeId Handle to vGPU type - * @param vgpuInstanceCount Pointer to get the max number of vGPU instances - * that can be created on a deicve for given vgpuTypeId - * @return - * - \ref NVML_SUCCESS successful completion - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid or is not supported on target device, - * or \a vgpuInstanceCount is NULL - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlVgpuTypeGetMaxInstances(nvmlDevice_t device, nvmlVgpuTypeId_t vgpuTypeId, unsigned int *vgpuInstanceCount); - -/** - * Retrieve the active vGPU instances on a device. - * - * An array of active vGPU instances is returned in the caller-supplied buffer pointed at by \a vgpuInstances. The - * array elememt count is passed in \a vgpuCount, and \a vgpuCount is used to return the number of vGPU instances - * written to the buffer. - * - * If the supplied buffer is not large enough to accomodate the vGPU instance array, the function returns - * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlVgpuInstance_t array required in \a vgpuCount. - * To query the number of active vGPU instances, call this function with *vgpuCount = 0. The code will return - * NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if no vGPU Types are supported. - * - * For Kepler &tm; or newer fully supported devices. - * - * @param device The identifier of the target device - * @param vgpuCount Pointer which passes in the array size as well as get - * back the number of types - * @param vgpuInstances Pointer to array in which to return list of vGPU instances - * - * @return - * - \ref NVML_SUCCESS successful completion - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a vgpuCount is NULL - * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a size is too small - * - \ref NVML_ERROR_NOT_SUPPORTED if vGPU is not supported by the device - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetActiveVgpus(nvmlDevice_t device, unsigned int *vgpuCount, nvmlVgpuInstance_t *vgpuInstances); - -/** - * Retrieve the VM ID associated with a vGPU instance. - * - * The VM ID is returned as a string, not exceeding 80 characters in length (including the NUL terminator). - * See \ref nvmlConstants::NVML_DEVICE_UUID_BUFFER_SIZE. - * - * The format of the VM ID varies by platform, and is indicated by the type identifier returned in \a vmIdType. - * - * For Kepler &tm; or newer fully supported devices. - * - * @param vgpuInstance Identifier of the target vGPU instance - * @param vmId Pointer to caller-supplied buffer to hold VM ID - * @param size Size of buffer in bytes - * @param vmIdType Pointer to hold VM ID type - * - * @return - * - \ref NVML_SUCCESS successful completion - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is invalid, or \a vmId or \a vmIdType are NULL - * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a size is too small - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlVgpuInstanceGetVmID(nvmlVgpuInstance_t vgpuInstance, char *vmId, unsigned int size, nvmlVgpuVmIdType_t *vmIdType); - -/** - * Retrieve the UUID of a vGPU instance. - * - * The UUID is a globally unique identifier associated with the vGPU, and is returned as a 5-part hexadecimal string, - * not exceeding 80 characters in length (including the NULL terminator). - * See \ref nvmlConstants::NVML_DEVICE_UUID_BUFFER_SIZE. - * - * For Kepler &tm; or newer fully supported devices. - * - * @param vgpuInstance Identifier of the target vGPU instance - * @param uuid Pointer to caller-supplied buffer to hold vGPU UUID - * @param size Size of buffer in bytes - * - * @return - * - \ref NVML_SUCCESS successful completion - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is invalid, or \a uuid is NULL - * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a size is too small - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlVgpuInstanceGetUUID(nvmlVgpuInstance_t vgpuInstance, char *uuid, unsigned int size); - -/** - * Retrieve the NVIDIA driver version installed in the VM associated with a vGPU. - * - * The version is returned as an alphanumeric string in the caller-supplied buffer \a version. The length of the version - * string will not exceed 80 characters in length (including the NUL terminator). - * See \ref nvmlConstants::NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE. - * - * nvmlVgpuInstanceGetVmDriverVersion() may be called at any time for a vGPU instance. The guest VM driver version is - * returned as "Unknown" if no NVIDIA driver is installed in the VM, or the VM has not yet booted to the point where the - * NVIDIA driver is loaded and initialized. - * - * For Kepler &tm; or newer fully supported devices. - * - * @param vgpuInstance Identifier of the target vGPU instance - * @param version Caller-supplied buffer to return driver version string - * @param length Size of \a version buffer - * - * @return - * - \ref NVML_SUCCESS if \a version has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is invalid - * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlVgpuInstanceGetVmDriverVersion(nvmlVgpuInstance_t vgpuInstance, char* version, unsigned int length); - -/** - * Retrieve the framebuffer usage in bytes. - * - * Framebuffer usage is the amont of vGPU framebuffer memory that is currently in use by the VM. - * - * For Kepler &tm; or newer fully supported devices. - * - * @param vgpuInstance The identifier of the target instance - * @param fbUsage Pointer to framebuffer usage in bytes - * - * @return - * - \ref NVML_SUCCESS successful completion - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is invalid, or \a fbUsage is NULL - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlVgpuInstanceGetFbUsage(nvmlVgpuInstance_t vgpuInstance, unsigned long long *fbUsage); - -/** - * Retrieve the current licensing state of the vGPU instance. - * - * If the vGPU is currently licensed, \a licensed is set to 1, otherwise it is set to 0. - * - * For Kepler &tm; or newer fully supported devices. - * - * @param vgpuInstance Identifier of the target vGPU instance - * @param licensed Reference to return the licensing status - * - * @return - * - \ref NVML_SUCCESS if \a licensed has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is invalid, or \a licensed is NULL - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlVgpuInstanceGetLicenseStatus(nvmlVgpuInstance_t vgpuInstance, unsigned int *licensed); - -/** - * Retrieve the vGPU type of a vGPU instance. - * - * Returns the vGPU type ID of vgpu assigned to the vGPU instance. - * - * For Kepler &tm; or newer fully supported devices. - * - * @param vgpuInstance Identifier of the target vGPU instance - * @param vgpuTypeId Reference to return the vgpuTypeId - * - * @return - * - \ref NVML_SUCCESS if \a vgpuTypeId has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is invalid, or \a vgpuTypeId is NULL - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlVgpuInstanceGetType(nvmlVgpuInstance_t vgpuInstance, nvmlVgpuTypeId_t *vgpuTypeId); - -/** - * Retrieve the frame rate limit set for the vGPU instance. - * - * Returns the value of the frame rate limit set for the vGPU instance - * - * For Kepler &tm; or newer fully supported devices. - * - * @param vgpuInstance Identifier of the target vGPU instance - * @param frameRateLimit Reference to return the frame rate limit - * - * @return - * - \ref NVML_SUCCESS if \a frameRateLimit has been set - * - \ref NVML_ERROR_NOT_SUPPORTED if frame rate limiter is turned off for the vGPU type - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is invalid, or \a frameRateLimit is NULL - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlVgpuInstanceGetFrameRateLimit(nvmlVgpuInstance_t vgpuInstance, unsigned int *frameRateLimit); - -/** - * Retrieve the encoder Capacity of a vGPU instance, in macroblocks per second. - * - * For Maxwell &tm; or newer fully supported devices. - * - * @param vgpuInstance Identifier of the target vGPU instance - * @param encoderCapacity Reference to an unsigned int for the encoder capacity - * - * @return - * - \ref NVML_SUCCESS if \a encoderCapacity has been retrived - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is invalid, or \a encoderQueryType is invalid - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlVgpuInstanceGetEncoderCapacity(nvmlVgpuInstance_t vgpuInstance, unsigned int *encoderCapacity); - -/** - * Set the encoder Capacity of a vGPU instance, in macroblocks per second. - * - * For Maxwell &tm; or newer fully supported devices. - * - * @param vgpuInstance Identifier of the target vGPU instance - * @param encoderCapacity Unsigned int for the encoder capacity value - * - * @return - * - \ref NVML_SUCCESS if \a encoderCapacity has been set - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is invalid - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlVgpuInstanceSetEncoderCapacity(nvmlVgpuInstance_t vgpuInstance, unsigned int encoderCapacity); - -/** - * Retrieves current utilization for vGPUs on a physical GPU (device). - * - * For Kepler &tm; or newer fully supported devices. - * - * Reads recent utilization of GPU SM (3D/Compute), framebuffer, video encoder, and video decoder for vGPU instances running - * on a device. Utilization values are returned as an array of utilization sample structures in the caller-supplied buffer - * pointed at by \a utilizationSamples. One utilization sample structure is returned per vGPU instance, and includes the - * CPU timestamp at which the samples were recorded. Individual utilization values are returned as "unsigned int" values - * in nvmlValue_t unions. The function sets the caller-supplied \a sampleValType to NVML_VALUE_TYPE_UNSIGNED_INT to - * indicate the returned value type. - * - * To read utilization values, first determine the size of buffer required to hold the samples by invoking the function with - * \a utilizationSamples set to NULL. The function will return NVML_ERROR_INSUFFICIENT_SIZE, with the current vGPU instance - * count in \a vgpuInstanceSamplesCount, or NVML_SUCCESS if the current vGPU instance count is zero. The caller should allocate - * a buffer of size vgpuInstanceSamplesCount * sizeof(nvmlVgpuInstanceUtilizationSample_t). Invoke the function again with - * the allocated buffer passed in \a utilizationSamples, and \a vgpuInstanceSamplesCount set to the number of entries the - * buffer is sized for. - * - * On successful return, the function updates \a vgpuInstanceSampleCount with the number of vGPU utilization sample - * structures that were actually written. This may differ from a previously read value as vGPU instances are created or - * destroyed. - * - * lastSeenTimeStamp represents the CPU timestamp in microseconds at which utilization samples were last read. Set it to 0 - * to read utilization based on all the samples maintained by the driver's internal sample buffer. Set lastSeenTimeStamp - * to a timeStamp retrieved from a previous query to read utilization since the previous query. - * - * @param device The identifier for the target device - * @param lastSeenTimeStamp Return only samples with timestamp greater than lastSeenTimeStamp. - * @param sampleValType Pointer to caller-supplied buffer to hold the type of returned sample values - * @param vgpuInstanceSamplesCount Pointer to caller-supplied array size, and returns number of vGPU instances - * @param utilizationSamples Pointer to caller-supplied buffer in which vGPU utilization samples are returned - - * @return - * - \ref NVML_SUCCESS if utilization samples are successfully retrieved - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a vgpuInstanceSamplesCount or \a sampleValType is - * NULL, or a sample count of 0 is passed with a non-NULL \a utilizationSamples - * - \ref NVML_ERROR_INSUFFICIENT_SIZE if supplied \a vgpuInstanceSamplesCount is too small to return samples for all - * vGPU instances currently executing on the device - * - \ref NVML_ERROR_NOT_SUPPORTED if vGPU is not supported by the device - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_NOT_FOUND if sample entries are not found - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetVgpuUtilization(nvmlDevice_t device, unsigned long long lastSeenTimeStamp, - nvmlValueType_t *sampleValType, unsigned int *vgpuInstanceSamplesCount, - nvmlVgpuInstanceUtilizationSample_t *utilizationSamples); - -/** - * Retrieves current utilization for processes running on vGPUs on a physical GPU (device). - * - * For Maxwell &tm; or newer fully supported devices. - * - * Reads recent utilization of GPU SM (3D/Compute), framebuffer, video encoder, and video decoder for processes running on - * vGPU instances active on a device. Utilization values are returned as an array of utilization sample structures in the - * caller-supplied buffer pointed at by \a utilizationSamples. One utilization sample structure is returned per process running - * on vGPU instances, that had some non-zero utilization during the last sample period. It includes the CPU timestamp at which - * the samples were recorded. Individual utilization values are returned as "unsigned int" values. - * - * To read utilization values, first determine the size of buffer required to hold the samples by invoking the function with - * \a utilizationSamples set to NULL. The function will return NVML_ERROR_INSUFFICIENT_SIZE, with the current vGPU instance - * count in \a vgpuProcessSamplesCount. The caller should allocate a buffer of size - * vgpuProcessSamplesCount * sizeof(nvmlVgpuProcessUtilizationSample_t). Invoke the function again with - * the allocated buffer passed in \a utilizationSamples, and \a vgpuProcessSamplesCount set to the number of entries the - * buffer is sized for. - * - * On successful return, the function updates \a vgpuSubProcessSampleCount with the number of vGPU sub process utilization sample - * structures that were actually written. This may differ from a previously read value depending on the number of processes that are active - * in any given sample period. - * - * lastSeenTimeStamp represents the CPU timestamp in microseconds at which utilization samples were last read. Set it to 0 - * to read utilization based on all the samples maintained by the driver's internal sample buffer. Set lastSeenTimeStamp - * to a timeStamp retrieved from a previous query to read utilization since the previous query. - * - * @param device The identifier for the target device - * @param lastSeenTimeStamp Return only samples with timestamp greater than lastSeenTimeStamp. - * @param vgpuProcessSamplesCount Pointer to caller-supplied array size, and returns number of processes running on vGPU instances - * @param utilizationSamples Pointer to caller-supplied buffer in which vGPU sub process utilization samples are returned - - * @return - * - \ref NVML_SUCCESS if utilization samples are successfully retrieved - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a vgpuProcessSamplesCount or a sample count of 0 is - * passed with a non-NULL \a utilizationSamples - * - \ref NVML_ERROR_INSUFFICIENT_SIZE if supplied \a vgpuProcessSamplesCount is too small to return samples for all - * vGPU instances currently executing on the device - * - \ref NVML_ERROR_NOT_SUPPORTED if vGPU is not supported by the device - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_NOT_FOUND if sample entries are not found - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetVgpuProcessUtilization(nvmlDevice_t device, unsigned long long lastSeenTimeStamp, - unsigned int *vgpuProcessSamplesCount, - nvmlVgpuProcessUtilizationSample_t *utilizationSamples); -/** - * Retrieve the GRID licensable features. - * - * Identifies whether the system supports GRID Software Licensing. If it does, return the list of licensable feature(s) - * and their current license status. - * - * @param device Identifier of the target device - * @param pGridLicensableFeatures Pointer to structure in which GRID licensable features are returned - * - * @return - * - \ref NVML_SUCCESS if licensable features are successfully retrieved - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a pGridLicensableFeatures is NULL - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetGridLicensableFeatures(nvmlDevice_t device, nvmlGridLicensableFeatures_t *pGridLicensableFeatures); - -/** - * Retrieves the current encoder statistics of a vGPU Instance - * - * For Maxwell &tm; or newer fully supported devices. - * - * @param vgpuInstance Identifier of the target vGPU instance - * @param sessionCount Reference to an unsigned int for count of active encoder sessions - * @param averageFps Reference to an unsigned int for trailing average FPS of all active sessions - * @param averageLatency Reference to an unsigned int for encode latency in microseconds - * - * @return - * - \ref NVML_SUCCESS if \a sessionCount, \a averageFps and \a averageLatency is fetched - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a sessionCount , or \a averageFps or \a averageLatency is NULL - * or \a vgpuInstance is invalid. - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlVgpuInstanceGetEncoderStats(nvmlVgpuInstance_t vgpuInstance, unsigned int *sessionCount, - unsigned int *averageFps, unsigned int *averageLatency); - -/** - * Retrieves information about all active encoder sessions on a vGPU Instance. - * - * An array of active encoder sessions is returned in the caller-supplied buffer pointed at by \a sessionInfo. The - * array elememt count is passed in \a sessionCount, and \a sessionCount is used to return the number of sessions - * written to the buffer. - * - * If the supplied buffer is not large enough to accomodate the active session array, the function returns - * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlEncoderSessionInfo_t array required in \a sessionCount. - * To query the number of active encoder sessions, call this function with *sessionCount = 0. The code will return - * NVML_SUCCESS with number of active encoder sessions updated in *sessionCount. - * - * For Maxwell &tm; or newer fully supported devices. - * - * @param vgpuInstance Identifier of the target vGPU instance - * @param sessionCount Reference to caller supplied array size, and returns - * the number of sessions. - * @param sessionInfo Reference to caller supplied array in which the list - * of session information us returned. - * - * @return - * - \ref NVML_SUCCESS if \a sessionInfo is fetched - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a sessionCount is too small, array element count is - returned in \a sessionCount - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a sessionCount is NULL or \a vgpuInstance is invalid.. - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlVgpuInstanceGetEncoderSessions(nvmlVgpuInstance_t vgpuInstance, unsigned int *sessionCount, nvmlEncoderSessionInfo_t *sessionInfo); - -/** - * Retrieves the current utilization and process ID - * - * For Maxwell &tm; or newer fully supported devices. - * - * Reads recent utilization of GPU SM (3D/Compute), framebuffer, video encoder, and video decoder for processes running. - * Utilization values are returned as an array of utilization sample structures in the caller-supplied buffer pointed at - * by \a utilization. One utilization sample structure is returned per process running, that had some non-zero utilization - * during the last sample period. It includes the CPU timestamp at which the samples were recorded. Individual utilization values - * are returned as "unsigned int" values. - * - * To read utilization values, first determine the size of buffer required to hold the samples by invoking the function with - * \a utilization set to NULL. The caller should allocate a buffer of size - * processSamplesCount * sizeof(nvmlProcessUtilizationSample_t). Invoke the function again with the allocated buffer passed - * in \a utilization, and \a processSamplesCount set to the number of entries the buffer is sized for. - * - * On successful return, the function updates \a processSamplesCount with the number of process utilization sample - * structures that were actually written. This may differ from a previously read value as instances are created or - * destroyed. - * - * lastSeenTimeStamp represents the CPU timestamp in microseconds at which utilization samples were last read. Set it to 0 - * to read utilization based on all the samples maintained by the driver's internal sample buffer. Set lastSeenTimeStamp - * to a timeStamp retrieved from a previous query to read utilization since the previous query. - * - * @param device The identifier of the target device - * @param utilization Pointer to caller-supplied buffer in which guest process utilization samples are returned - * @param processSamplesCount Pointer to caller-supplied array size, and returns number of processes running - * @param lastSeenTimeStamp Return only samples with timestamp greater than lastSeenTimeStamp. - - * @return - * - \ref NVML_SUCCESS if \a utilization has been populated - * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized - * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a utilization is NULL, or \a samplingPeriodUs is NULL - * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature - * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible - * - \ref NVML_ERROR_UNKNOWN on any unexpected error - */ -nvmlReturn_t DECLDIR nvmlDeviceGetProcessUtilization(nvmlDevice_t device, nvmlProcessUtilizationSample_t *utilization, - unsigned int *processSamplesCount, unsigned long long lastSeenTimeStamp); - -/** @} */ - -/** - * NVML API versioning support - */ -#if defined(__NVML_API_VERSION_INTERNAL) -#undef nvmlDeviceGetPciInfo -#undef nvmlDeviceGetCount -#undef nvmlDeviceGetHandleByIndex -#undef nvmlDeviceGetHandleByPciBusId -#undef nvmlInit -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/vendor/github.com/prometheus/client_golang/AUTHORS.md b/vendor/github.com/prometheus/client_golang/AUTHORS.md deleted file mode 100644 index c5275d5..0000000 --- a/vendor/github.com/prometheus/client_golang/AUTHORS.md +++ /dev/null @@ -1,18 +0,0 @@ -The Prometheus project was started by Matt T. Proud (emeritus) and -Julius Volz in 2012. - -Maintainers of this repository: - -* Björn Rabenstein - -The following individuals have contributed code to this repository -(listed in alphabetical order): - -* Bernerd Schaefer -* Björn Rabenstein -* Daniel Bornkessel -* Jeff Younker -* Julius Volz -* Matt T. Proud -* Tobias Schmidt - diff --git a/vendor/github.com/prometheus/client_golang/LICENSE b/vendor/github.com/prometheus/client_golang/LICENSE deleted file mode 100644 index 261eeb9..0000000 --- a/vendor/github.com/prometheus/client_golang/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. diff --git a/vendor/github.com/prometheus/client_golang/NOTICE b/vendor/github.com/prometheus/client_golang/NOTICE deleted file mode 100644 index dd878a3..0000000 --- a/vendor/github.com/prometheus/client_golang/NOTICE +++ /dev/null @@ -1,23 +0,0 @@ -Prometheus instrumentation library for Go applications -Copyright 2012-2015 The Prometheus Authors - -This product includes software developed at -SoundCloud Ltd. (http://soundcloud.com/). - - -The following components are included in this product: - -perks - a fork of https://github.com/bmizerany/perks -https://github.com/beorn7/perks -Copyright 2013-2015 Blake Mizerany, Björn Rabenstein -See https://github.com/beorn7/perks/blob/master/README.md for license details. - -Go support for Protocol Buffers - Google's data interchange format -http://github.com/golang/protobuf/ -Copyright 2010 The Go Authors -See source code for license details. - -Support for streaming Protocol Buffer messages for the Go language (golang). -https://github.com/matttproud/golang_protobuf_extensions -Copyright 2013 Matt T. Proud -Licensed under the Apache License, Version 2.0 diff --git a/vendor/github.com/prometheus/client_golang/prometheus/.gitignore b/vendor/github.com/prometheus/client_golang/prometheus/.gitignore deleted file mode 100644 index 3460f03..0000000 --- a/vendor/github.com/prometheus/client_golang/prometheus/.gitignore +++ /dev/null @@ -1 +0,0 @@ -command-line-arguments.test diff --git a/vendor/github.com/prometheus/client_golang/prometheus/README.md b/vendor/github.com/prometheus/client_golang/prometheus/README.md deleted file mode 100644 index 44986bf..0000000 --- a/vendor/github.com/prometheus/client_golang/prometheus/README.md +++ /dev/null @@ -1 +0,0 @@ -See [![go-doc](https://godoc.org/github.com/prometheus/client_golang/prometheus?status.svg)](https://godoc.org/github.com/prometheus/client_golang/prometheus). diff --git a/vendor/github.com/prometheus/client_golang/prometheus/collector.go b/vendor/github.com/prometheus/client_golang/prometheus/collector.go deleted file mode 100644 index 623d3d8..0000000 --- a/vendor/github.com/prometheus/client_golang/prometheus/collector.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2014 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. - -package prometheus - -// Collector is the interface implemented by anything that can be used by -// Prometheus to collect metrics. A Collector has to be registered for -// collection. See Registerer.Register. -// -// The stock metrics provided by this package (Gauge, Counter, Summary, -// Histogram, Untyped) are also Collectors (which only ever collect one metric, -// namely itself). An implementer of Collector may, however, collect multiple -// metrics in a coordinated fashion and/or create metrics on the fly. Examples -// for collectors already implemented in this library are the metric vectors -// (i.e. collection of multiple instances of the same Metric but with different -// label values) like GaugeVec or SummaryVec, and the ExpvarCollector. -type Collector interface { - // Describe sends the super-set of all possible descriptors of metrics - // collected by this Collector to the provided channel and returns once - // the last descriptor has been sent. The sent descriptors fulfill the - // consistency and uniqueness requirements described in the Desc - // documentation. (It is valid if one and the same Collector sends - // duplicate descriptors. Those duplicates are simply ignored. However, - // two different Collectors must not send duplicate descriptors.) This - // method idempotently sends the same descriptors throughout the - // lifetime of the Collector. If a Collector encounters an error while - // executing this method, it must send an invalid descriptor (created - // with NewInvalidDesc) to signal the error to the registry. - Describe(chan<- *Desc) - // Collect is called by the Prometheus registry when collecting - // metrics. The implementation sends each collected metric via the - // provided channel and returns once the last metric has been sent. The - // descriptor of each sent metric is one of those returned by - // Describe. Returned metrics that share the same descriptor must differ - // in their variable label values. This method may be called - // concurrently and must therefore be implemented in a concurrency safe - // way. Blocking occurs at the expense of total performance of rendering - // all registered metrics. Ideally, Collector implementations support - // concurrent readers. - Collect(chan<- Metric) -} - -// selfCollector implements Collector for a single Metric so that the Metric -// collects itself. Add it as an anonymous field to a struct that implements -// Metric, and call init with the Metric itself as an argument. -type selfCollector struct { - self Metric -} - -// init provides the selfCollector with a reference to the metric it is supposed -// to collect. It is usually called within the factory function to create a -// metric. See example. -func (c *selfCollector) init(self Metric) { - c.self = self -} - -// Describe implements Collector. -func (c *selfCollector) Describe(ch chan<- *Desc) { - ch <- c.self.Desc() -} - -// Collect implements Collector. -func (c *selfCollector) Collect(ch chan<- Metric) { - ch <- c.self -} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/counter.go b/vendor/github.com/prometheus/client_golang/prometheus/counter.go deleted file mode 100644 index ee37949..0000000 --- a/vendor/github.com/prometheus/client_golang/prometheus/counter.go +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 2014 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. - -package prometheus - -import ( - "errors" -) - -// Counter is a Metric that represents a single numerical value that only ever -// goes up. That implies that it cannot be used to count items whose number can -// also go down, e.g. the number of currently running goroutines. Those -// "counters" are represented by Gauges. -// -// A Counter is typically used to count requests served, tasks completed, errors -// occurred, etc. -// -// To create Counter instances, use NewCounter. -type Counter interface { - Metric - Collector - - // Set is used to set the Counter to an arbitrary value. It is only used - // if you have to transfer a value from an external counter into this - // Prometheus metric. Do not use it for regular handling of a - // Prometheus counter (as it can be used to break the contract of - // monotonically increasing values). - // - // Deprecated: Use NewConstMetric to create a counter for an external - // value. A Counter should never be set. - Set(float64) - // Inc increments the counter by 1. - Inc() - // Add adds the given value to the counter. It panics if the value is < - // 0. - Add(float64) -} - -// CounterOpts is an alias for Opts. See there for doc comments. -type CounterOpts Opts - -// NewCounter creates a new Counter based on the provided CounterOpts. -func NewCounter(opts CounterOpts) Counter { - desc := NewDesc( - BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), - opts.Help, - nil, - opts.ConstLabels, - ) - result := &counter{value: value{desc: desc, valType: CounterValue, labelPairs: desc.constLabelPairs}} - result.init(result) // Init self-collection. - return result -} - -type counter struct { - value -} - -func (c *counter) Add(v float64) { - if v < 0 { - panic(errors.New("counter cannot decrease in value")) - } - c.value.Add(v) -} - -// CounterVec is a Collector that bundles a set of Counters that all share the -// same Desc, but have different values for their variable labels. This is used -// if you want to count the same thing partitioned by various dimensions -// (e.g. number of HTTP requests, partitioned by response code and -// method). Create instances with NewCounterVec. -// -// CounterVec embeds MetricVec. See there for a full list of methods with -// detailed documentation. -type CounterVec struct { - *MetricVec -} - -// NewCounterVec creates a new CounterVec based on the provided CounterOpts and -// partitioned by the given label names. At least one label name must be -// provided. -func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec { - desc := NewDesc( - BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), - opts.Help, - labelNames, - opts.ConstLabels, - ) - return &CounterVec{ - MetricVec: newMetricVec(desc, func(lvs ...string) Metric { - result := &counter{value: value{ - desc: desc, - valType: CounterValue, - labelPairs: makeLabelPairs(desc, lvs), - }} - result.init(result) // Init self-collection. - return result - }), - } -} - -// GetMetricWithLabelValues replaces the method of the same name in -// MetricVec. The difference is that this method returns a Counter and not a -// Metric so that no type conversion is required. -func (m *CounterVec) GetMetricWithLabelValues(lvs ...string) (Counter, error) { - metric, err := m.MetricVec.GetMetricWithLabelValues(lvs...) - if metric != nil { - return metric.(Counter), err - } - return nil, err -} - -// GetMetricWith replaces the method of the same name in MetricVec. The -// difference is that this method returns a Counter and not a Metric so that no -// type conversion is required. -func (m *CounterVec) GetMetricWith(labels Labels) (Counter, error) { - metric, err := m.MetricVec.GetMetricWith(labels) - if metric != nil { - return metric.(Counter), err - } - return nil, err -} - -// WithLabelValues works as GetMetricWithLabelValues, but panics where -// GetMetricWithLabelValues would have returned an error. By not returning an -// error, WithLabelValues allows shortcuts like -// myVec.WithLabelValues("404", "GET").Add(42) -func (m *CounterVec) WithLabelValues(lvs ...string) Counter { - return m.MetricVec.WithLabelValues(lvs...).(Counter) -} - -// With works as GetMetricWith, but panics where GetMetricWithLabels would have -// returned an error. By not returning an error, With allows shortcuts like -// myVec.With(Labels{"code": "404", "method": "GET"}).Add(42) -func (m *CounterVec) With(labels Labels) Counter { - return m.MetricVec.With(labels).(Counter) -} - -// CounterFunc is a Counter whose value is determined at collect time by calling a -// provided function. -// -// To create CounterFunc instances, use NewCounterFunc. -type CounterFunc interface { - Metric - Collector -} - -// NewCounterFunc creates a new CounterFunc based on the provided -// CounterOpts. The value reported is determined by calling the given function -// from within the Write method. Take into account that metric collection may -// happen concurrently. If that results in concurrent calls to Write, like in -// the case where a CounterFunc is directly registered with Prometheus, the -// provided function must be concurrency-safe. The function should also honor -// the contract for a Counter (values only go up, not down), but compliance will -// not be checked. -func NewCounterFunc(opts CounterOpts, function func() float64) CounterFunc { - return newValueFunc(NewDesc( - BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), - opts.Help, - nil, - opts.ConstLabels, - ), CounterValue, function) -} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/desc.go b/vendor/github.com/prometheus/client_golang/prometheus/desc.go deleted file mode 100644 index 77f4b30..0000000 --- a/vendor/github.com/prometheus/client_golang/prometheus/desc.go +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright 2016 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. - -package prometheus - -import ( - "errors" - "fmt" - "regexp" - "sort" - "strings" - - "github.com/golang/protobuf/proto" - - dto "github.com/prometheus/client_model/go" -) - -var ( - metricNameRE = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_:]*$`) - labelNameRE = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_]*$") -) - -// reservedLabelPrefix is a prefix which is not legal in user-supplied -// label names. -const reservedLabelPrefix = "__" - -// Labels represents a collection of label name -> value mappings. This type is -// commonly used with the With(Labels) and GetMetricWith(Labels) methods of -// metric vector Collectors, e.g.: -// myVec.With(Labels{"code": "404", "method": "GET"}).Add(42) -// -// The other use-case is the specification of constant label pairs in Opts or to -// create a Desc. -type Labels map[string]string - -// Desc is the descriptor used by every Prometheus Metric. It is essentially -// the immutable meta-data of a Metric. The normal Metric implementations -// included in this package manage their Desc under the hood. Users only have to -// deal with Desc if they use advanced features like the ExpvarCollector or -// custom Collectors and Metrics. -// -// Descriptors registered with the same registry have to fulfill certain -// consistency and uniqueness criteria if they share the same fully-qualified -// name: They must have the same help string and the same label names (aka label -// dimensions) in each, constLabels and variableLabels, but they must differ in -// the values of the constLabels. -// -// Descriptors that share the same fully-qualified names and the same label -// values of their constLabels are considered equal. -// -// Use NewDesc to create new Desc instances. -type Desc struct { - // fqName has been built from Namespace, Subsystem, and Name. - fqName string - // help provides some helpful information about this metric. - help string - // constLabelPairs contains precalculated DTO label pairs based on - // the constant labels. - constLabelPairs []*dto.LabelPair - // VariableLabels contains names of labels for which the metric - // maintains variable values. - variableLabels []string - // id is a hash of the values of the ConstLabels and fqName. This - // must be unique among all registered descriptors and can therefore be - // used as an identifier of the descriptor. - id uint64 - // dimHash is a hash of the label names (preset and variable) and the - // Help string. Each Desc with the same fqName must have the same - // dimHash. - dimHash uint64 - // err is an error that occured during construction. It is reported on - // registration time. - err error -} - -// NewDesc allocates and initializes a new Desc. Errors are recorded in the Desc -// and will be reported on registration time. variableLabels and constLabels can -// be nil if no such labels should be set. fqName and help must not be empty. -// -// variableLabels only contain the label names. Their label values are variable -// and therefore not part of the Desc. (They are managed within the Metric.) -// -// For constLabels, the label values are constant. Therefore, they are fully -// specified in the Desc. See the Opts documentation for the implications of -// constant labels. -func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) *Desc { - d := &Desc{ - fqName: fqName, - help: help, - variableLabels: variableLabels, - } - if help == "" { - d.err = errors.New("empty help string") - return d - } - if !metricNameRE.MatchString(fqName) { - d.err = fmt.Errorf("%q is not a valid metric name", fqName) - return d - } - // labelValues contains the label values of const labels (in order of - // their sorted label names) plus the fqName (at position 0). - labelValues := make([]string, 1, len(constLabels)+1) - labelValues[0] = fqName - labelNames := make([]string, 0, len(constLabels)+len(variableLabels)) - labelNameSet := map[string]struct{}{} - // First add only the const label names and sort them... - for labelName := range constLabels { - if !checkLabelName(labelName) { - d.err = fmt.Errorf("%q is not a valid label name", labelName) - return d - } - labelNames = append(labelNames, labelName) - labelNameSet[labelName] = struct{}{} - } - sort.Strings(labelNames) - // ... so that we can now add const label values in the order of their names. - for _, labelName := range labelNames { - labelValues = append(labelValues, constLabels[labelName]) - } - // Now add the variable label names, but prefix them with something that - // cannot be in a regular label name. That prevents matching the label - // dimension with a different mix between preset and variable labels. - for _, labelName := range variableLabels { - if !checkLabelName(labelName) { - d.err = fmt.Errorf("%q is not a valid label name", labelName) - return d - } - labelNames = append(labelNames, "$"+labelName) - labelNameSet[labelName] = struct{}{} - } - if len(labelNames) != len(labelNameSet) { - d.err = errors.New("duplicate label names") - return d - } - vh := hashNew() - for _, val := range labelValues { - vh = hashAdd(vh, val) - vh = hashAddByte(vh, separatorByte) - } - d.id = vh - // Sort labelNames so that order doesn't matter for the hash. - sort.Strings(labelNames) - // Now hash together (in this order) the help string and the sorted - // label names. - lh := hashNew() - lh = hashAdd(lh, help) - lh = hashAddByte(lh, separatorByte) - for _, labelName := range labelNames { - lh = hashAdd(lh, labelName) - lh = hashAddByte(lh, separatorByte) - } - d.dimHash = lh - - d.constLabelPairs = make([]*dto.LabelPair, 0, len(constLabels)) - for n, v := range constLabels { - d.constLabelPairs = append(d.constLabelPairs, &dto.LabelPair{ - Name: proto.String(n), - Value: proto.String(v), - }) - } - sort.Sort(LabelPairSorter(d.constLabelPairs)) - return d -} - -// NewInvalidDesc returns an invalid descriptor, i.e. a descriptor with the -// provided error set. If a collector returning such a descriptor is registered, -// registration will fail with the provided error. NewInvalidDesc can be used by -// a Collector to signal inability to describe itself. -func NewInvalidDesc(err error) *Desc { - return &Desc{ - err: err, - } -} - -func (d *Desc) String() string { - lpStrings := make([]string, 0, len(d.constLabelPairs)) - for _, lp := range d.constLabelPairs { - lpStrings = append( - lpStrings, - fmt.Sprintf("%s=%q", lp.GetName(), lp.GetValue()), - ) - } - return fmt.Sprintf( - "Desc{fqName: %q, help: %q, constLabels: {%s}, variableLabels: %v}", - d.fqName, - d.help, - strings.Join(lpStrings, ","), - d.variableLabels, - ) -} - -func checkLabelName(l string) bool { - return labelNameRE.MatchString(l) && - !strings.HasPrefix(l, reservedLabelPrefix) -} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/doc.go b/vendor/github.com/prometheus/client_golang/prometheus/doc.go deleted file mode 100644 index b15a2d3..0000000 --- a/vendor/github.com/prometheus/client_golang/prometheus/doc.go +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright 2014 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. - -// Package prometheus provides metrics primitives to instrument code for -// monitoring. It also offers a registry for metrics. Sub-packages allow to -// expose the registered metrics via HTTP (package promhttp) or push them to a -// Pushgateway (package push). -// -// All exported functions and methods are safe to be used concurrently unless -//specified otherwise. -// -// A Basic Example -// -// As a starting point, a very basic usage example: -// -// package main -// -// import ( -// "net/http" -// -// "github.com/prometheus/client_golang/prometheus" -// "github.com/prometheus/client_golang/prometheus/promhttp" -// ) -// -// var ( -// cpuTemp = prometheus.NewGauge(prometheus.GaugeOpts{ -// Name: "cpu_temperature_celsius", -// Help: "Current temperature of the CPU.", -// }) -// hdFailures = prometheus.NewCounterVec( -// prometheus.CounterOpts{ -// Name: "hd_errors_total", -// Help: "Number of hard-disk errors.", -// }, -// []string{"device"}, -// ) -// ) -// -// func init() { -// // Metrics have to be registered to be exposed: -// prometheus.MustRegister(cpuTemp) -// prometheus.MustRegister(hdFailures) -// } -// -// func main() { -// cpuTemp.Set(65.3) -// hdFailures.With(prometheus.Labels{"device":"/dev/sda"}).Inc() -// -// // The Handler function provides a default handler to expose metrics -// // via an HTTP server. "/metrics" is the usual endpoint for that. -// http.Handle("/metrics", promhttp.Handler()) -// http.ListenAndServe(":8080", nil) -// } -// -// -// This is a complete program that exports two metrics, a Gauge and a Counter, -// the latter with a label attached to turn it into a (one-dimensional) vector. -// -// Metrics -// -// The number of exported identifiers in this package might appear a bit -// overwhelming. Hovever, in addition to the basic plumbing shown in the example -// above, you only need to understand the different metric types and their -// vector versions for basic usage. -// -// Above, you have already touched the Counter and the Gauge. There are two more -// advanced metric types: the Summary and Histogram. A more thorough description -// of those four metric types can be found in the Prometheus docs: -// https://prometheus.io/docs/concepts/metric_types/ -// -// A fifth "type" of metric is Untyped. It behaves like a Gauge, but signals the -// Prometheus server not to assume anything about its type. -// -// In addition to the fundamental metric types Gauge, Counter, Summary, -// Histogram, and Untyped, a very important part of the Prometheus data model is -// the partitioning of samples along dimensions called labels, which results in -// metric vectors. The fundamental types are GaugeVec, CounterVec, SummaryVec, -// HistogramVec, and UntypedVec. -// -// While only the fundamental metric types implement the Metric interface, both -// the metrics and their vector versions implement the Collector interface. A -// Collector manages the collection of a number of Metrics, but for convenience, -// a Metric can also “collect itself”. Note that Gauge, Counter, Summary, -// Histogram, and Untyped are interfaces themselves while GaugeVec, CounterVec, -// SummaryVec, HistogramVec, and UntypedVec are not. -// -// To create instances of Metrics and their vector versions, you need a suitable -// …Opts struct, i.e. GaugeOpts, CounterOpts, SummaryOpts, -// HistogramOpts, or UntypedOpts. -// -// Custom Collectors and constant Metrics -// -// While you could create your own implementations of Metric, most likely you -// will only ever implement the Collector interface on your own. At a first -// glance, a custom Collector seems handy to bundle Metrics for common -// registration (with the prime example of the different metric vectors above, -// which bundle all the metrics of the same name but with different labels). -// -// There is a more involved use case, too: If you already have metrics -// available, created outside of the Prometheus context, you don't need the -// interface of the various Metric types. You essentially want to mirror the -// existing numbers into Prometheus Metrics during collection. An own -// implementation of the Collector interface is perfect for that. You can create -// Metric instances “on the fly” using NewConstMetric, NewConstHistogram, and -// NewConstSummary (and their respective Must… versions). That will happen in -// the Collect method. The Describe method has to return separate Desc -// instances, representative of the “throw-away” metrics to be created -// later. NewDesc comes in handy to create those Desc instances. -// -// The Collector example illustrates the use case. You can also look at the -// source code of the processCollector (mirroring process metrics), the -// goCollector (mirroring Go metrics), or the expvarCollector (mirroring expvar -// metrics) as examples that are used in this package itself. -// -// If you just need to call a function to get a single float value to collect as -// a metric, GaugeFunc, CounterFunc, or UntypedFunc might be interesting -// shortcuts. -// -// Advanced Uses of the Registry -// -// While MustRegister is the by far most common way of registering a Collector, -// sometimes you might want to handle the errors the registration might -// cause. As suggested by the name, MustRegister panics if an error occurs. With -// the Register function, the error is returned and can be handled. -// -// An error is returned if the registered Collector is incompatible or -// inconsistent with already registered metrics. The registry aims for -// consistency of the collected metrics according to the Prometheus data -// model. Inconsistencies are ideally detected at registration time, not at -// collect time. The former will usually be detected at start-up time of a -// program, while the latter will only happen at scrape time, possibly not even -// on the first scrape if the inconsistency only becomes relevant later. That is -// the main reason why a Collector and a Metric have to describe themselves to -// the registry. -// -// So far, everything we did operated on the so-called default registry, as it -// can be found in the global DefaultRegistry variable. With NewRegistry, you -// can create a custom registry, or you can even implement the Registerer or -// Gatherer interfaces yourself. The methods Register and Unregister work in -// the same way on a custom registry as the global functions Register and -// Unregister on the default registry. -// -// There are a number of uses for custom registries: You can use registries -// with special properties, see NewPedanticRegistry. You can avoid global state, -// as it is imposed by the DefaultRegistry. You can use multiple registries at -// the same time to expose different metrics in different ways. You can use -// separate registries for testing purposes. -// -// Also note that the DefaultRegistry comes registered with a Collector for Go -// runtime metrics (via NewGoCollector) and a Collector for process metrics (via -// NewProcessCollector). With a custom registry, you are in control and decide -// yourself about the Collectors to register. -// -// HTTP Exposition -// -// The Registry implements the Gatherer interface. The caller of the Gather -// method can then expose the gathered metrics in some way. Usually, the metrics -// are served via HTTP on the /metrics endpoint. That's happening in the example -// above. The tools to expose metrics via HTTP are in the promhttp -// sub-package. (The top-level functions in the prometheus package are -// deprecated.) -// -// Pushing to the Pushgateway -// -// Function for pushing to the Pushgateway can be found in the push sub-package. -// -// Other Means of Exposition -// -// More ways of exposing metrics can easily be added. Sending metrics to -// Graphite would be an example that will soon be implemented. -package prometheus diff --git a/vendor/github.com/prometheus/client_golang/prometheus/expvar_collector.go b/vendor/github.com/prometheus/client_golang/prometheus/expvar_collector.go deleted file mode 100644 index 18a99d5..0000000 --- a/vendor/github.com/prometheus/client_golang/prometheus/expvar_collector.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2014 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. - -package prometheus - -import ( - "encoding/json" - "expvar" -) - -type expvarCollector struct { - exports map[string]*Desc -} - -// NewExpvarCollector returns a newly allocated expvar Collector that still has -// to be registered with a Prometheus registry. -// -// An expvar Collector collects metrics from the expvar interface. It provides a -// quick way to expose numeric values that are already exported via expvar as -// Prometheus metrics. Note that the data models of expvar and Prometheus are -// fundamentally different, and that the expvar Collector is inherently slower -// than native Prometheus metrics. Thus, the expvar Collector is probably great -// for experiments and prototying, but you should seriously consider a more -// direct implementation of Prometheus metrics for monitoring production -// systems. -// -// The exports map has the following meaning: -// -// The keys in the map correspond to expvar keys, i.e. for every expvar key you -// want to export as Prometheus metric, you need an entry in the exports -// map. The descriptor mapped to each key describes how to export the expvar -// value. It defines the name and the help string of the Prometheus metric -// proxying the expvar value. The type will always be Untyped. -// -// For descriptors without variable labels, the expvar value must be a number or -// a bool. The number is then directly exported as the Prometheus sample -// value. (For a bool, 'false' translates to 0 and 'true' to 1). Expvar values -// that are not numbers or bools are silently ignored. -// -// If the descriptor has one variable label, the expvar value must be an expvar -// map. The keys in the expvar map become the various values of the one -// Prometheus label. The values in the expvar map must be numbers or bools again -// as above. -// -// For descriptors with more than one variable label, the expvar must be a -// nested expvar map, i.e. where the values of the topmost map are maps again -// etc. until a depth is reached that corresponds to the number of labels. The -// leaves of that structure must be numbers or bools as above to serve as the -// sample values. -// -// Anything that does not fit into the scheme above is silently ignored. -func NewExpvarCollector(exports map[string]*Desc) Collector { - return &expvarCollector{ - exports: exports, - } -} - -// Describe implements Collector. -func (e *expvarCollector) Describe(ch chan<- *Desc) { - for _, desc := range e.exports { - ch <- desc - } -} - -// Collect implements Collector. -func (e *expvarCollector) Collect(ch chan<- Metric) { - for name, desc := range e.exports { - var m Metric - expVar := expvar.Get(name) - if expVar == nil { - continue - } - var v interface{} - labels := make([]string, len(desc.variableLabels)) - if err := json.Unmarshal([]byte(expVar.String()), &v); err != nil { - ch <- NewInvalidMetric(desc, err) - continue - } - var processValue func(v interface{}, i int) - processValue = func(v interface{}, i int) { - if i >= len(labels) { - copiedLabels := append(make([]string, 0, len(labels)), labels...) - switch v := v.(type) { - case float64: - m = MustNewConstMetric(desc, UntypedValue, v, copiedLabels...) - case bool: - if v { - m = MustNewConstMetric(desc, UntypedValue, 1, copiedLabels...) - } else { - m = MustNewConstMetric(desc, UntypedValue, 0, copiedLabels...) - } - default: - return - } - ch <- m - return - } - vm, ok := v.(map[string]interface{}) - if !ok { - return - } - for lv, val := range vm { - labels[i] = lv - processValue(val, i+1) - } - } - processValue(v, 0) - } -} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/fnv.go b/vendor/github.com/prometheus/client_golang/prometheus/fnv.go deleted file mode 100644 index e3b67df..0000000 --- a/vendor/github.com/prometheus/client_golang/prometheus/fnv.go +++ /dev/null @@ -1,29 +0,0 @@ -package prometheus - -// Inline and byte-free variant of hash/fnv's fnv64a. - -const ( - offset64 = 14695981039346656037 - prime64 = 1099511628211 -) - -// hashNew initializies a new fnv64a hash value. -func hashNew() uint64 { - return offset64 -} - -// hashAdd adds a string to a fnv64a hash value, returning the updated hash. -func hashAdd(h uint64, s string) uint64 { - for i := 0; i < len(s); i++ { - h ^= uint64(s[i]) - h *= prime64 - } - return h -} - -// hashAddByte adds a byte to a fnv64a hash value, returning the updated hash. -func hashAddByte(h uint64, b byte) uint64 { - h ^= uint64(b) - h *= prime64 - return h -} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/gauge.go b/vendor/github.com/prometheus/client_golang/prometheus/gauge.go deleted file mode 100644 index 8b70e51..0000000 --- a/vendor/github.com/prometheus/client_golang/prometheus/gauge.go +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2014 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. - -package prometheus - -// Gauge is a Metric that represents a single numerical value that can -// arbitrarily go up and down. -// -// A Gauge is typically used for measured values like temperatures or current -// memory usage, but also "counts" that can go up and down, like the number of -// running goroutines. -// -// To create Gauge instances, use NewGauge. -type Gauge interface { - Metric - Collector - - // Set sets the Gauge to an arbitrary value. - Set(float64) - // Inc increments the Gauge by 1. - Inc() - // Dec decrements the Gauge by 1. - Dec() - // Add adds the given value to the Gauge. (The value can be - // negative, resulting in a decrease of the Gauge.) - Add(float64) - // Sub subtracts the given value from the Gauge. (The value can be - // negative, resulting in an increase of the Gauge.) - Sub(float64) -} - -// GaugeOpts is an alias for Opts. See there for doc comments. -type GaugeOpts Opts - -// NewGauge creates a new Gauge based on the provided GaugeOpts. -func NewGauge(opts GaugeOpts) Gauge { - return newValue(NewDesc( - BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), - opts.Help, - nil, - opts.ConstLabels, - ), GaugeValue, 0) -} - -// GaugeVec is a Collector that bundles a set of Gauges that all share the same -// Desc, but have different values for their variable labels. This is used if -// you want to count the same thing partitioned by various dimensions -// (e.g. number of operations queued, partitioned by user and operation -// type). Create instances with NewGaugeVec. -type GaugeVec struct { - *MetricVec -} - -// NewGaugeVec creates a new GaugeVec based on the provided GaugeOpts and -// partitioned by the given label names. At least one label name must be -// provided. -func NewGaugeVec(opts GaugeOpts, labelNames []string) *GaugeVec { - desc := NewDesc( - BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), - opts.Help, - labelNames, - opts.ConstLabels, - ) - return &GaugeVec{ - MetricVec: newMetricVec(desc, func(lvs ...string) Metric { - return newValue(desc, GaugeValue, 0, lvs...) - }), - } -} - -// GetMetricWithLabelValues replaces the method of the same name in -// MetricVec. The difference is that this method returns a Gauge and not a -// Metric so that no type conversion is required. -func (m *GaugeVec) GetMetricWithLabelValues(lvs ...string) (Gauge, error) { - metric, err := m.MetricVec.GetMetricWithLabelValues(lvs...) - if metric != nil { - return metric.(Gauge), err - } - return nil, err -} - -// GetMetricWith replaces the method of the same name in MetricVec. The -// difference is that this method returns a Gauge and not a Metric so that no -// type conversion is required. -func (m *GaugeVec) GetMetricWith(labels Labels) (Gauge, error) { - metric, err := m.MetricVec.GetMetricWith(labels) - if metric != nil { - return metric.(Gauge), err - } - return nil, err -} - -// WithLabelValues works as GetMetricWithLabelValues, but panics where -// GetMetricWithLabelValues would have returned an error. By not returning an -// error, WithLabelValues allows shortcuts like -// myVec.WithLabelValues("404", "GET").Add(42) -func (m *GaugeVec) WithLabelValues(lvs ...string) Gauge { - return m.MetricVec.WithLabelValues(lvs...).(Gauge) -} - -// With works as GetMetricWith, but panics where GetMetricWithLabels would have -// returned an error. By not returning an error, With allows shortcuts like -// myVec.With(Labels{"code": "404", "method": "GET"}).Add(42) -func (m *GaugeVec) With(labels Labels) Gauge { - return m.MetricVec.With(labels).(Gauge) -} - -// GaugeFunc is a Gauge whose value is determined at collect time by calling a -// provided function. -// -// To create GaugeFunc instances, use NewGaugeFunc. -type GaugeFunc interface { - Metric - Collector -} - -// NewGaugeFunc creates a new GaugeFunc based on the provided GaugeOpts. The -// value reported is determined by calling the given function from within the -// Write method. Take into account that metric collection may happen -// concurrently. If that results in concurrent calls to Write, like in the case -// where a GaugeFunc is directly registered with Prometheus, the provided -// function must be concurrency-safe. -func NewGaugeFunc(opts GaugeOpts, function func() float64) GaugeFunc { - return newValueFunc(NewDesc( - BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), - opts.Help, - nil, - opts.ConstLabels, - ), GaugeValue, function) -} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/go_collector.go b/vendor/github.com/prometheus/client_golang/prometheus/go_collector.go deleted file mode 100644 index abc9d4e..0000000 --- a/vendor/github.com/prometheus/client_golang/prometheus/go_collector.go +++ /dev/null @@ -1,263 +0,0 @@ -package prometheus - -import ( - "fmt" - "runtime" - "runtime/debug" - "time" -) - -type goCollector struct { - goroutines Gauge - gcDesc *Desc - - // metrics to describe and collect - metrics memStatsMetrics -} - -// NewGoCollector returns a collector which exports metrics about the current -// go process. -func NewGoCollector() Collector { - return &goCollector{ - goroutines: NewGauge(GaugeOpts{ - Namespace: "go", - Name: "goroutines", - Help: "Number of goroutines that currently exist.", - }), - gcDesc: NewDesc( - "go_gc_duration_seconds", - "A summary of the GC invocation durations.", - nil, nil), - metrics: memStatsMetrics{ - { - desc: NewDesc( - memstatNamespace("alloc_bytes"), - "Number of bytes allocated and still in use.", - nil, nil, - ), - eval: func(ms *runtime.MemStats) float64 { return float64(ms.Alloc) }, - valType: GaugeValue, - }, { - desc: NewDesc( - memstatNamespace("alloc_bytes_total"), - "Total number of bytes allocated, even if freed.", - nil, nil, - ), - eval: func(ms *runtime.MemStats) float64 { return float64(ms.TotalAlloc) }, - valType: CounterValue, - }, { - desc: NewDesc( - memstatNamespace("sys_bytes"), - "Number of bytes obtained by system. Sum of all system allocations.", - nil, nil, - ), - eval: func(ms *runtime.MemStats) float64 { return float64(ms.Sys) }, - valType: GaugeValue, - }, { - desc: NewDesc( - memstatNamespace("lookups_total"), - "Total number of pointer lookups.", - nil, nil, - ), - eval: func(ms *runtime.MemStats) float64 { return float64(ms.Lookups) }, - valType: CounterValue, - }, { - desc: NewDesc( - memstatNamespace("mallocs_total"), - "Total number of mallocs.", - nil, nil, - ), - eval: func(ms *runtime.MemStats) float64 { return float64(ms.Mallocs) }, - valType: CounterValue, - }, { - desc: NewDesc( - memstatNamespace("frees_total"), - "Total number of frees.", - nil, nil, - ), - eval: func(ms *runtime.MemStats) float64 { return float64(ms.Frees) }, - valType: CounterValue, - }, { - desc: NewDesc( - memstatNamespace("heap_alloc_bytes"), - "Number of heap bytes allocated and still in use.", - nil, nil, - ), - eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapAlloc) }, - valType: GaugeValue, - }, { - desc: NewDesc( - memstatNamespace("heap_sys_bytes"), - "Number of heap bytes obtained from system.", - nil, nil, - ), - eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapSys) }, - valType: GaugeValue, - }, { - desc: NewDesc( - memstatNamespace("heap_idle_bytes"), - "Number of heap bytes waiting to be used.", - nil, nil, - ), - eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapIdle) }, - valType: GaugeValue, - }, { - desc: NewDesc( - memstatNamespace("heap_inuse_bytes"), - "Number of heap bytes that are in use.", - nil, nil, - ), - eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapInuse) }, - valType: GaugeValue, - }, { - desc: NewDesc( - memstatNamespace("heap_released_bytes_total"), - "Total number of heap bytes released to OS.", - nil, nil, - ), - eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapReleased) }, - valType: CounterValue, - }, { - desc: NewDesc( - memstatNamespace("heap_objects"), - "Number of allocated objects.", - nil, nil, - ), - eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapObjects) }, - valType: GaugeValue, - }, { - desc: NewDesc( - memstatNamespace("stack_inuse_bytes"), - "Number of bytes in use by the stack allocator.", - nil, nil, - ), - eval: func(ms *runtime.MemStats) float64 { return float64(ms.StackInuse) }, - valType: GaugeValue, - }, { - desc: NewDesc( - memstatNamespace("stack_sys_bytes"), - "Number of bytes obtained from system for stack allocator.", - nil, nil, - ), - eval: func(ms *runtime.MemStats) float64 { return float64(ms.StackSys) }, - valType: GaugeValue, - }, { - desc: NewDesc( - memstatNamespace("mspan_inuse_bytes"), - "Number of bytes in use by mspan structures.", - nil, nil, - ), - eval: func(ms *runtime.MemStats) float64 { return float64(ms.MSpanInuse) }, - valType: GaugeValue, - }, { - desc: NewDesc( - memstatNamespace("mspan_sys_bytes"), - "Number of bytes used for mspan structures obtained from system.", - nil, nil, - ), - eval: func(ms *runtime.MemStats) float64 { return float64(ms.MSpanSys) }, - valType: GaugeValue, - }, { - desc: NewDesc( - memstatNamespace("mcache_inuse_bytes"), - "Number of bytes in use by mcache structures.", - nil, nil, - ), - eval: func(ms *runtime.MemStats) float64 { return float64(ms.MCacheInuse) }, - valType: GaugeValue, - }, { - desc: NewDesc( - memstatNamespace("mcache_sys_bytes"), - "Number of bytes used for mcache structures obtained from system.", - nil, nil, - ), - eval: func(ms *runtime.MemStats) float64 { return float64(ms.MCacheSys) }, - valType: GaugeValue, - }, { - desc: NewDesc( - memstatNamespace("buck_hash_sys_bytes"), - "Number of bytes used by the profiling bucket hash table.", - nil, nil, - ), - eval: func(ms *runtime.MemStats) float64 { return float64(ms.BuckHashSys) }, - valType: GaugeValue, - }, { - desc: NewDesc( - memstatNamespace("gc_sys_bytes"), - "Number of bytes used for garbage collection system metadata.", - nil, nil, - ), - eval: func(ms *runtime.MemStats) float64 { return float64(ms.GCSys) }, - valType: GaugeValue, - }, { - desc: NewDesc( - memstatNamespace("other_sys_bytes"), - "Number of bytes used for other system allocations.", - nil, nil, - ), - eval: func(ms *runtime.MemStats) float64 { return float64(ms.OtherSys) }, - valType: GaugeValue, - }, { - desc: NewDesc( - memstatNamespace("next_gc_bytes"), - "Number of heap bytes when next garbage collection will take place.", - nil, nil, - ), - eval: func(ms *runtime.MemStats) float64 { return float64(ms.NextGC) }, - valType: GaugeValue, - }, { - desc: NewDesc( - memstatNamespace("last_gc_time_seconds"), - "Number of seconds since 1970 of last garbage collection.", - nil, nil, - ), - eval: func(ms *runtime.MemStats) float64 { return float64(ms.LastGC) / 1e9 }, - valType: GaugeValue, - }, - }, - } -} - -func memstatNamespace(s string) string { - return fmt.Sprintf("go_memstats_%s", s) -} - -// Describe returns all descriptions of the collector. -func (c *goCollector) Describe(ch chan<- *Desc) { - ch <- c.goroutines.Desc() - ch <- c.gcDesc - - for _, i := range c.metrics { - ch <- i.desc - } -} - -// Collect returns the current state of all metrics of the collector. -func (c *goCollector) Collect(ch chan<- Metric) { - c.goroutines.Set(float64(runtime.NumGoroutine())) - ch <- c.goroutines - - var stats debug.GCStats - stats.PauseQuantiles = make([]time.Duration, 5) - debug.ReadGCStats(&stats) - - quantiles := make(map[float64]float64) - for idx, pq := range stats.PauseQuantiles[1:] { - quantiles[float64(idx+1)/float64(len(stats.PauseQuantiles)-1)] = pq.Seconds() - } - quantiles[0.0] = stats.PauseQuantiles[0].Seconds() - ch <- MustNewConstSummary(c.gcDesc, uint64(stats.NumGC), float64(stats.PauseTotal.Seconds()), quantiles) - - ms := &runtime.MemStats{} - runtime.ReadMemStats(ms) - for _, i := range c.metrics { - ch <- MustNewConstMetric(i.desc, i.valType, i.eval(ms)) - } -} - -// memStatsMetrics provide description, value, and value type for memstat metrics. -type memStatsMetrics []struct { - desc *Desc - eval func(*runtime.MemStats) float64 - valType ValueType -} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/histogram.go b/vendor/github.com/prometheus/client_golang/prometheus/histogram.go deleted file mode 100644 index 9719e8f..0000000 --- a/vendor/github.com/prometheus/client_golang/prometheus/histogram.go +++ /dev/null @@ -1,444 +0,0 @@ -// Copyright 2015 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. - -package prometheus - -import ( - "fmt" - "math" - "sort" - "sync/atomic" - - "github.com/golang/protobuf/proto" - - dto "github.com/prometheus/client_model/go" -) - -// A Histogram counts individual observations from an event or sample stream in -// configurable buckets. Similar to a summary, it also provides a sum of -// observations and an observation count. -// -// On the Prometheus server, quantiles can be calculated from a Histogram using -// the histogram_quantile function in the query language. -// -// Note that Histograms, in contrast to Summaries, can be aggregated with the -// Prometheus query language (see the documentation for detailed -// procedures). However, Histograms require the user to pre-define suitable -// buckets, and they are in general less accurate. The Observe method of a -// Histogram has a very low performance overhead in comparison with the Observe -// method of a Summary. -// -// To create Histogram instances, use NewHistogram. -type Histogram interface { - Metric - Collector - - // Observe adds a single observation to the histogram. - Observe(float64) -} - -// bucketLabel is used for the label that defines the upper bound of a -// bucket of a histogram ("le" -> "less or equal"). -const bucketLabel = "le" - -// DefBuckets are the default Histogram buckets. The default buckets are -// tailored to broadly measure the response time (in seconds) of a network -// service. Most likely, however, you will be required to define buckets -// customized to your use case. -var ( - DefBuckets = []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10} - - errBucketLabelNotAllowed = fmt.Errorf( - "%q is not allowed as label name in histograms", bucketLabel, - ) -) - -// LinearBuckets creates 'count' buckets, each 'width' wide, where the lowest -// bucket has an upper bound of 'start'. The final +Inf bucket is not counted -// and not included in the returned slice. The returned slice is meant to be -// used for the Buckets field of HistogramOpts. -// -// The function panics if 'count' is zero or negative. -func LinearBuckets(start, width float64, count int) []float64 { - if count < 1 { - panic("LinearBuckets needs a positive count") - } - buckets := make([]float64, count) - for i := range buckets { - buckets[i] = start - start += width - } - return buckets -} - -// ExponentialBuckets creates 'count' buckets, where the lowest bucket has an -// upper bound of 'start' and each following bucket's upper bound is 'factor' -// times the previous bucket's upper bound. The final +Inf bucket is not counted -// and not included in the returned slice. The returned slice is meant to be -// used for the Buckets field of HistogramOpts. -// -// The function panics if 'count' is 0 or negative, if 'start' is 0 or negative, -// or if 'factor' is less than or equal 1. -func ExponentialBuckets(start, factor float64, count int) []float64 { - if count < 1 { - panic("ExponentialBuckets needs a positive count") - } - if start <= 0 { - panic("ExponentialBuckets needs a positive start value") - } - if factor <= 1 { - panic("ExponentialBuckets needs a factor greater than 1") - } - buckets := make([]float64, count) - for i := range buckets { - buckets[i] = start - start *= factor - } - return buckets -} - -// HistogramOpts bundles the options for creating a Histogram metric. It is -// mandatory to set Name and Help to a non-empty string. All other fields are -// optional and can safely be left at their zero value. -type HistogramOpts struct { - // Namespace, Subsystem, and Name are components of the fully-qualified - // name of the Histogram (created by joining these components with - // "_"). Only Name is mandatory, the others merely help structuring the - // name. Note that the fully-qualified name of the Histogram must be a - // valid Prometheus metric name. - Namespace string - Subsystem string - Name string - - // Help provides information about this Histogram. Mandatory! - // - // Metrics with the same fully-qualified name must have the same Help - // string. - Help string - - // ConstLabels are used to attach fixed labels to this - // Histogram. Histograms with the same fully-qualified name must have the - // same label names in their ConstLabels. - // - // Note that in most cases, labels have a value that varies during the - // lifetime of a process. Those labels are usually managed with a - // HistogramVec. ConstLabels serve only special purposes. One is for the - // special case where the value of a label does not change during the - // lifetime of a process, e.g. if the revision of the running binary is - // put into a label. Another, more advanced purpose is if more than one - // Collector needs to collect Histograms with the same fully-qualified - // name. In that case, those Summaries must differ in the values of - // their ConstLabels. See the Collector examples. - // - // If the value of a label never changes (not even between binaries), - // that label most likely should not be a label at all (but part of the - // metric name). - ConstLabels Labels - - // Buckets defines the buckets into which observations are counted. Each - // element in the slice is the upper inclusive bound of a bucket. The - // values must be sorted in strictly increasing order. There is no need - // to add a highest bucket with +Inf bound, it will be added - // implicitly. The default value is DefBuckets. - Buckets []float64 -} - -// NewHistogram creates a new Histogram based on the provided HistogramOpts. It -// panics if the buckets in HistogramOpts are not in strictly increasing order. -func NewHistogram(opts HistogramOpts) Histogram { - return newHistogram( - NewDesc( - BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), - opts.Help, - nil, - opts.ConstLabels, - ), - opts, - ) -} - -func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogram { - if len(desc.variableLabels) != len(labelValues) { - panic(errInconsistentCardinality) - } - - for _, n := range desc.variableLabels { - if n == bucketLabel { - panic(errBucketLabelNotAllowed) - } - } - for _, lp := range desc.constLabelPairs { - if lp.GetName() == bucketLabel { - panic(errBucketLabelNotAllowed) - } - } - - if len(opts.Buckets) == 0 { - opts.Buckets = DefBuckets - } - - h := &histogram{ - desc: desc, - upperBounds: opts.Buckets, - labelPairs: makeLabelPairs(desc, labelValues), - } - for i, upperBound := range h.upperBounds { - if i < len(h.upperBounds)-1 { - if upperBound >= h.upperBounds[i+1] { - panic(fmt.Errorf( - "histogram buckets must be in increasing order: %f >= %f", - upperBound, h.upperBounds[i+1], - )) - } - } else { - if math.IsInf(upperBound, +1) { - // The +Inf bucket is implicit. Remove it here. - h.upperBounds = h.upperBounds[:i] - } - } - } - // Finally we know the final length of h.upperBounds and can make counts. - h.counts = make([]uint64, len(h.upperBounds)) - - h.init(h) // Init self-collection. - return h -} - -type histogram struct { - // sumBits contains the bits of the float64 representing the sum of all - // observations. sumBits and count have to go first in the struct to - // guarantee alignment for atomic operations. - // http://golang.org/pkg/sync/atomic/#pkg-note-BUG - sumBits uint64 - count uint64 - - selfCollector - // Note that there is no mutex required. - - desc *Desc - - upperBounds []float64 - counts []uint64 - - labelPairs []*dto.LabelPair -} - -func (h *histogram) Desc() *Desc { - return h.desc -} - -func (h *histogram) Observe(v float64) { - // TODO(beorn7): For small numbers of buckets (<30), a linear search is - // slightly faster than the binary search. If we really care, we could - // switch from one search strategy to the other depending on the number - // of buckets. - // - // Microbenchmarks (BenchmarkHistogramNoLabels): - // 11 buckets: 38.3 ns/op linear - binary 48.7 ns/op - // 100 buckets: 78.1 ns/op linear - binary 54.9 ns/op - // 300 buckets: 154 ns/op linear - binary 61.6 ns/op - i := sort.SearchFloat64s(h.upperBounds, v) - if i < len(h.counts) { - atomic.AddUint64(&h.counts[i], 1) - } - atomic.AddUint64(&h.count, 1) - for { - oldBits := atomic.LoadUint64(&h.sumBits) - newBits := math.Float64bits(math.Float64frombits(oldBits) + v) - if atomic.CompareAndSwapUint64(&h.sumBits, oldBits, newBits) { - break - } - } -} - -func (h *histogram) Write(out *dto.Metric) error { - his := &dto.Histogram{} - buckets := make([]*dto.Bucket, len(h.upperBounds)) - - his.SampleSum = proto.Float64(math.Float64frombits(atomic.LoadUint64(&h.sumBits))) - his.SampleCount = proto.Uint64(atomic.LoadUint64(&h.count)) - var count uint64 - for i, upperBound := range h.upperBounds { - count += atomic.LoadUint64(&h.counts[i]) - buckets[i] = &dto.Bucket{ - CumulativeCount: proto.Uint64(count), - UpperBound: proto.Float64(upperBound), - } - } - his.Bucket = buckets - out.Histogram = his - out.Label = h.labelPairs - return nil -} - -// HistogramVec is a Collector that bundles a set of Histograms that all share the -// same Desc, but have different values for their variable labels. This is used -// if you want to count the same thing partitioned by various dimensions -// (e.g. HTTP request latencies, partitioned by status code and method). Create -// instances with NewHistogramVec. -type HistogramVec struct { - *MetricVec -} - -// NewHistogramVec creates a new HistogramVec based on the provided HistogramOpts and -// partitioned by the given label names. At least one label name must be -// provided. -func NewHistogramVec(opts HistogramOpts, labelNames []string) *HistogramVec { - desc := NewDesc( - BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), - opts.Help, - labelNames, - opts.ConstLabels, - ) - return &HistogramVec{ - MetricVec: newMetricVec(desc, func(lvs ...string) Metric { - return newHistogram(desc, opts, lvs...) - }), - } -} - -// GetMetricWithLabelValues replaces the method of the same name in -// MetricVec. The difference is that this method returns a Histogram and not a -// Metric so that no type conversion is required. -func (m *HistogramVec) GetMetricWithLabelValues(lvs ...string) (Histogram, error) { - metric, err := m.MetricVec.GetMetricWithLabelValues(lvs...) - if metric != nil { - return metric.(Histogram), err - } - return nil, err -} - -// GetMetricWith replaces the method of the same name in MetricVec. The -// difference is that this method returns a Histogram and not a Metric so that no -// type conversion is required. -func (m *HistogramVec) GetMetricWith(labels Labels) (Histogram, error) { - metric, err := m.MetricVec.GetMetricWith(labels) - if metric != nil { - return metric.(Histogram), err - } - return nil, err -} - -// WithLabelValues works as GetMetricWithLabelValues, but panics where -// GetMetricWithLabelValues would have returned an error. By not returning an -// error, WithLabelValues allows shortcuts like -// myVec.WithLabelValues("404", "GET").Observe(42.21) -func (m *HistogramVec) WithLabelValues(lvs ...string) Histogram { - return m.MetricVec.WithLabelValues(lvs...).(Histogram) -} - -// With works as GetMetricWith, but panics where GetMetricWithLabels would have -// returned an error. By not returning an error, With allows shortcuts like -// myVec.With(Labels{"code": "404", "method": "GET"}).Observe(42.21) -func (m *HistogramVec) With(labels Labels) Histogram { - return m.MetricVec.With(labels).(Histogram) -} - -type constHistogram struct { - desc *Desc - count uint64 - sum float64 - buckets map[float64]uint64 - labelPairs []*dto.LabelPair -} - -func (h *constHistogram) Desc() *Desc { - return h.desc -} - -func (h *constHistogram) Write(out *dto.Metric) error { - his := &dto.Histogram{} - buckets := make([]*dto.Bucket, 0, len(h.buckets)) - - his.SampleCount = proto.Uint64(h.count) - his.SampleSum = proto.Float64(h.sum) - - for upperBound, count := range h.buckets { - buckets = append(buckets, &dto.Bucket{ - CumulativeCount: proto.Uint64(count), - UpperBound: proto.Float64(upperBound), - }) - } - - if len(buckets) > 0 { - sort.Sort(buckSort(buckets)) - } - his.Bucket = buckets - - out.Histogram = his - out.Label = h.labelPairs - - return nil -} - -// NewConstHistogram returns a metric representing a Prometheus histogram with -// fixed values for the count, sum, and bucket counts. As those parameters -// cannot be changed, the returned value does not implement the Histogram -// interface (but only the Metric interface). Users of this package will not -// have much use for it in regular operations. However, when implementing custom -// Collectors, it is useful as a throw-away metric that is generated on the fly -// to send it to Prometheus in the Collect method. -// -// buckets is a map of upper bounds to cumulative counts, excluding the +Inf -// bucket. -// -// NewConstHistogram returns an error if the length of labelValues is not -// consistent with the variable labels in Desc. -func NewConstHistogram( - desc *Desc, - count uint64, - sum float64, - buckets map[float64]uint64, - labelValues ...string, -) (Metric, error) { - if len(desc.variableLabels) != len(labelValues) { - return nil, errInconsistentCardinality - } - return &constHistogram{ - desc: desc, - count: count, - sum: sum, - buckets: buckets, - labelPairs: makeLabelPairs(desc, labelValues), - }, nil -} - -// MustNewConstHistogram is a version of NewConstHistogram that panics where -// NewConstMetric would have returned an error. -func MustNewConstHistogram( - desc *Desc, - count uint64, - sum float64, - buckets map[float64]uint64, - labelValues ...string, -) Metric { - m, err := NewConstHistogram(desc, count, sum, buckets, labelValues...) - if err != nil { - panic(err) - } - return m -} - -type buckSort []*dto.Bucket - -func (s buckSort) Len() int { - return len(s) -} - -func (s buckSort) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -func (s buckSort) Less(i, j int) bool { - return s[i].GetUpperBound() < s[j].GetUpperBound() -} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/http.go b/vendor/github.com/prometheus/client_golang/prometheus/http.go deleted file mode 100644 index 67ee5ac..0000000 --- a/vendor/github.com/prometheus/client_golang/prometheus/http.go +++ /dev/null @@ -1,490 +0,0 @@ -// Copyright 2014 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. - -package prometheus - -import ( - "bufio" - "bytes" - "compress/gzip" - "fmt" - "io" - "net" - "net/http" - "strconv" - "strings" - "sync" - "time" - - "github.com/prometheus/common/expfmt" -) - -// TODO(beorn7): Remove this whole file. It is a partial mirror of -// promhttp/http.go (to avoid circular import chains) where everything HTTP -// related should live. The functions here are just for avoiding -// breakage. Everything is deprecated. - -const ( - contentTypeHeader = "Content-Type" - contentLengthHeader = "Content-Length" - contentEncodingHeader = "Content-Encoding" - acceptEncodingHeader = "Accept-Encoding" -) - -var bufPool sync.Pool - -func getBuf() *bytes.Buffer { - buf := bufPool.Get() - if buf == nil { - return &bytes.Buffer{} - } - return buf.(*bytes.Buffer) -} - -func giveBuf(buf *bytes.Buffer) { - buf.Reset() - bufPool.Put(buf) -} - -// Handler returns an HTTP handler for the DefaultGatherer. It is -// already instrumented with InstrumentHandler (using "prometheus" as handler -// name). -// -// Deprecated: Please note the issues described in the doc comment of -// InstrumentHandler. You might want to consider using promhttp.Handler instead -// (which is non instrumented). -func Handler() http.Handler { - return InstrumentHandler("prometheus", UninstrumentedHandler()) -} - -// UninstrumentedHandler returns an HTTP handler for the DefaultGatherer. -// -// Deprecated: Use promhttp.Handler instead. See there for further documentation. -func UninstrumentedHandler() http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - mfs, err := DefaultGatherer.Gather() - if err != nil { - http.Error(w, "An error has occurred during metrics collection:\n\n"+err.Error(), http.StatusInternalServerError) - return - } - - contentType := expfmt.Negotiate(req.Header) - buf := getBuf() - defer giveBuf(buf) - writer, encoding := decorateWriter(req, buf) - enc := expfmt.NewEncoder(writer, contentType) - var lastErr error - for _, mf := range mfs { - if err := enc.Encode(mf); err != nil { - lastErr = err - http.Error(w, "An error has occurred during metrics encoding:\n\n"+err.Error(), http.StatusInternalServerError) - return - } - } - if closer, ok := writer.(io.Closer); ok { - closer.Close() - } - if lastErr != nil && buf.Len() == 0 { - http.Error(w, "No metrics encoded, last error:\n\n"+err.Error(), http.StatusInternalServerError) - return - } - header := w.Header() - header.Set(contentTypeHeader, string(contentType)) - header.Set(contentLengthHeader, fmt.Sprint(buf.Len())) - if encoding != "" { - header.Set(contentEncodingHeader, encoding) - } - w.Write(buf.Bytes()) - }) -} - -// decorateWriter wraps a writer to handle gzip compression if requested. It -// returns the decorated writer and the appropriate "Content-Encoding" header -// (which is empty if no compression is enabled). -func decorateWriter(request *http.Request, writer io.Writer) (io.Writer, string) { - header := request.Header.Get(acceptEncodingHeader) - parts := strings.Split(header, ",") - for _, part := range parts { - part := strings.TrimSpace(part) - if part == "gzip" || strings.HasPrefix(part, "gzip;") { - return gzip.NewWriter(writer), "gzip" - } - } - return writer, "" -} - -var instLabels = []string{"method", "code"} - -type nower interface { - Now() time.Time -} - -type nowFunc func() time.Time - -func (n nowFunc) Now() time.Time { - return n() -} - -var now nower = nowFunc(func() time.Time { - return time.Now() -}) - -func nowSeries(t ...time.Time) nower { - return nowFunc(func() time.Time { - defer func() { - t = t[1:] - }() - - return t[0] - }) -} - -// InstrumentHandler wraps the given HTTP handler for instrumentation. It -// registers four metric collectors (if not already done) and reports HTTP -// metrics to the (newly or already) registered collectors: http_requests_total -// (CounterVec), http_request_duration_microseconds (Summary), -// http_request_size_bytes (Summary), http_response_size_bytes (Summary). Each -// has a constant label named "handler" with the provided handlerName as -// value. http_requests_total is a metric vector partitioned by HTTP method -// (label name "method") and HTTP status code (label name "code"). -// -// Deprecated: InstrumentHandler has several issues: -// -// - It uses Summaries rather than Histograms. Summaries are not useful if -// aggregation across multiple instances is required. -// -// - It uses microseconds as unit, which is deprecated and should be replaced by -// seconds. -// -// - The size of the request is calculated in a separate goroutine. Since this -// calculator requires access to the request header, it creates a race with -// any writes to the header performed during request handling. -// httputil.ReverseProxy is a prominent example for a handler -// performing such writes. -// -// Upcoming versions of this package will provide ways of instrumenting HTTP -// handlers that are more flexible and have fewer issues. Please prefer direct -// instrumentation in the meantime. -func InstrumentHandler(handlerName string, handler http.Handler) http.HandlerFunc { - return InstrumentHandlerFunc(handlerName, handler.ServeHTTP) -} - -// InstrumentHandlerFunc wraps the given function for instrumentation. It -// otherwise works in the same way as InstrumentHandler (and shares the same -// issues). -// -// Deprecated: InstrumentHandlerFunc is deprecated for the same reasons as -// InstrumentHandler is. -func InstrumentHandlerFunc(handlerName string, handlerFunc func(http.ResponseWriter, *http.Request)) http.HandlerFunc { - return InstrumentHandlerFuncWithOpts( - SummaryOpts{ - Subsystem: "http", - ConstLabels: Labels{"handler": handlerName}, - }, - handlerFunc, - ) -} - -// InstrumentHandlerWithOpts works like InstrumentHandler (and shares the same -// issues) but provides more flexibility (at the cost of a more complex call -// syntax). As InstrumentHandler, this function registers four metric -// collectors, but it uses the provided SummaryOpts to create them. However, the -// fields "Name" and "Help" in the SummaryOpts are ignored. "Name" is replaced -// by "requests_total", "request_duration_microseconds", "request_size_bytes", -// and "response_size_bytes", respectively. "Help" is replaced by an appropriate -// help string. The names of the variable labels of the http_requests_total -// CounterVec are "method" (get, post, etc.), and "code" (HTTP status code). -// -// If InstrumentHandlerWithOpts is called as follows, it mimics exactly the -// behavior of InstrumentHandler: -// -// prometheus.InstrumentHandlerWithOpts( -// prometheus.SummaryOpts{ -// Subsystem: "http", -// ConstLabels: prometheus.Labels{"handler": handlerName}, -// }, -// handler, -// ) -// -// Technical detail: "requests_total" is a CounterVec, not a SummaryVec, so it -// cannot use SummaryOpts. Instead, a CounterOpts struct is created internally, -// and all its fields are set to the equally named fields in the provided -// SummaryOpts. -// -// Deprecated: InstrumentHandlerWithOpts is deprecated for the same reasons as -// InstrumentHandler is. -func InstrumentHandlerWithOpts(opts SummaryOpts, handler http.Handler) http.HandlerFunc { - return InstrumentHandlerFuncWithOpts(opts, handler.ServeHTTP) -} - -// InstrumentHandlerFuncWithOpts works like InstrumentHandlerFunc (and shares -// the same issues) but provides more flexibility (at the cost of a more complex -// call syntax). See InstrumentHandlerWithOpts for details how the provided -// SummaryOpts are used. -// -// Deprecated: InstrumentHandlerFuncWithOpts is deprecated for the same reasons -// as InstrumentHandler is. -func InstrumentHandlerFuncWithOpts(opts SummaryOpts, handlerFunc func(http.ResponseWriter, *http.Request)) http.HandlerFunc { - reqCnt := NewCounterVec( - CounterOpts{ - Namespace: opts.Namespace, - Subsystem: opts.Subsystem, - Name: "requests_total", - Help: "Total number of HTTP requests made.", - ConstLabels: opts.ConstLabels, - }, - instLabels, - ) - - opts.Name = "request_duration_microseconds" - opts.Help = "The HTTP request latencies in microseconds." - reqDur := NewSummary(opts) - - opts.Name = "request_size_bytes" - opts.Help = "The HTTP request sizes in bytes." - reqSz := NewSummary(opts) - - opts.Name = "response_size_bytes" - opts.Help = "The HTTP response sizes in bytes." - resSz := NewSummary(opts) - - regReqCnt := MustRegisterOrGet(reqCnt).(*CounterVec) - regReqDur := MustRegisterOrGet(reqDur).(Summary) - regReqSz := MustRegisterOrGet(reqSz).(Summary) - regResSz := MustRegisterOrGet(resSz).(Summary) - - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - now := time.Now() - - delegate := &responseWriterDelegator{ResponseWriter: w} - out := make(chan int) - urlLen := 0 - if r.URL != nil { - urlLen = len(r.URL.String()) - } - go computeApproximateRequestSize(r, out, urlLen) - - _, cn := w.(http.CloseNotifier) - _, fl := w.(http.Flusher) - _, hj := w.(http.Hijacker) - _, rf := w.(io.ReaderFrom) - var rw http.ResponseWriter - if cn && fl && hj && rf { - rw = &fancyResponseWriterDelegator{delegate} - } else { - rw = delegate - } - handlerFunc(rw, r) - - elapsed := float64(time.Since(now)) / float64(time.Microsecond) - - method := sanitizeMethod(r.Method) - code := sanitizeCode(delegate.status) - regReqCnt.WithLabelValues(method, code).Inc() - regReqDur.Observe(elapsed) - regResSz.Observe(float64(delegate.written)) - regReqSz.Observe(float64(<-out)) - }) -} - -func computeApproximateRequestSize(r *http.Request, out chan int, s int) { - s += len(r.Method) - s += len(r.Proto) - for name, values := range r.Header { - s += len(name) - for _, value := range values { - s += len(value) - } - } - s += len(r.Host) - - // N.B. r.Form and r.MultipartForm are assumed to be included in r.URL. - - if r.ContentLength != -1 { - s += int(r.ContentLength) - } - out <- s -} - -type responseWriterDelegator struct { - http.ResponseWriter - - handler, method string - status int - written int64 - wroteHeader bool -} - -func (r *responseWriterDelegator) WriteHeader(code int) { - r.status = code - r.wroteHeader = true - r.ResponseWriter.WriteHeader(code) -} - -func (r *responseWriterDelegator) Write(b []byte) (int, error) { - if !r.wroteHeader { - r.WriteHeader(http.StatusOK) - } - n, err := r.ResponseWriter.Write(b) - r.written += int64(n) - return n, err -} - -type fancyResponseWriterDelegator struct { - *responseWriterDelegator -} - -func (f *fancyResponseWriterDelegator) CloseNotify() <-chan bool { - return f.ResponseWriter.(http.CloseNotifier).CloseNotify() -} - -func (f *fancyResponseWriterDelegator) Flush() { - f.ResponseWriter.(http.Flusher).Flush() -} - -func (f *fancyResponseWriterDelegator) Hijack() (net.Conn, *bufio.ReadWriter, error) { - return f.ResponseWriter.(http.Hijacker).Hijack() -} - -func (f *fancyResponseWriterDelegator) ReadFrom(r io.Reader) (int64, error) { - if !f.wroteHeader { - f.WriteHeader(http.StatusOK) - } - n, err := f.ResponseWriter.(io.ReaderFrom).ReadFrom(r) - f.written += n - return n, err -} - -func sanitizeMethod(m string) string { - switch m { - case "GET", "get": - return "get" - case "PUT", "put": - return "put" - case "HEAD", "head": - return "head" - case "POST", "post": - return "post" - case "DELETE", "delete": - return "delete" - case "CONNECT", "connect": - return "connect" - case "OPTIONS", "options": - return "options" - case "NOTIFY", "notify": - return "notify" - default: - return strings.ToLower(m) - } -} - -func sanitizeCode(s int) string { - switch s { - case 100: - return "100" - case 101: - return "101" - - case 200: - return "200" - case 201: - return "201" - case 202: - return "202" - case 203: - return "203" - case 204: - return "204" - case 205: - return "205" - case 206: - return "206" - - case 300: - return "300" - case 301: - return "301" - case 302: - return "302" - case 304: - return "304" - case 305: - return "305" - case 307: - return "307" - - case 400: - return "400" - case 401: - return "401" - case 402: - return "402" - case 403: - return "403" - case 404: - return "404" - case 405: - return "405" - case 406: - return "406" - case 407: - return "407" - case 408: - return "408" - case 409: - return "409" - case 410: - return "410" - case 411: - return "411" - case 412: - return "412" - case 413: - return "413" - case 414: - return "414" - case 415: - return "415" - case 416: - return "416" - case 417: - return "417" - case 418: - return "418" - - case 500: - return "500" - case 501: - return "501" - case 502: - return "502" - case 503: - return "503" - case 504: - return "504" - case 505: - return "505" - - case 428: - return "428" - case 429: - return "429" - case 431: - return "431" - case 511: - return "511" - - default: - return strconv.Itoa(s) - } -} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/metric.go b/vendor/github.com/prometheus/client_golang/prometheus/metric.go deleted file mode 100644 index d4063d9..0000000 --- a/vendor/github.com/prometheus/client_golang/prometheus/metric.go +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2014 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. - -package prometheus - -import ( - "strings" - - dto "github.com/prometheus/client_model/go" -) - -const separatorByte byte = 255 - -// A Metric models a single sample value with its meta data being exported to -// Prometheus. Implementations of Metric in this package are Gauge, Counter, -// Histogram, Summary, and Untyped. -type Metric interface { - // Desc returns the descriptor for the Metric. This method idempotently - // returns the same descriptor throughout the lifetime of the - // Metric. The returned descriptor is immutable by contract. A Metric - // unable to describe itself must return an invalid descriptor (created - // with NewInvalidDesc). - Desc() *Desc - // Write encodes the Metric into a "Metric" Protocol Buffer data - // transmission object. - // - // Metric implementations must observe concurrency safety as reads of - // this metric may occur at any time, and any blocking occurs at the - // expense of total performance of rendering all registered - // metrics. Ideally, Metric implementations should support concurrent - // readers. - // - // While populating dto.Metric, it is the responsibility of the - // implementation to ensure validity of the Metric protobuf (like valid - // UTF-8 strings or syntactically valid metric and label names). It is - // recommended to sort labels lexicographically. (Implementers may find - // LabelPairSorter useful for that.) Callers of Write should still make - // sure of sorting if they depend on it. - Write(*dto.Metric) error - // TODO(beorn7): The original rationale of passing in a pre-allocated - // dto.Metric protobuf to save allocations has disappeared. The - // signature of this method should be changed to "Write() (*dto.Metric, - // error)". -} - -// Opts bundles the options for creating most Metric types. Each metric -// implementation XXX has its own XXXOpts type, but in most cases, it is just be -// an alias of this type (which might change when the requirement arises.) -// -// It is mandatory to set Name and Help to a non-empty string. All other fields -// are optional and can safely be left at their zero value. -type Opts struct { - // Namespace, Subsystem, and Name are components of the fully-qualified - // name of the Metric (created by joining these components with - // "_"). Only Name is mandatory, the others merely help structuring the - // name. Note that the fully-qualified name of the metric must be a - // valid Prometheus metric name. - Namespace string - Subsystem string - Name string - - // Help provides information about this metric. Mandatory! - // - // Metrics with the same fully-qualified name must have the same Help - // string. - Help string - - // ConstLabels are used to attach fixed labels to this metric. Metrics - // with the same fully-qualified name must have the same label names in - // their ConstLabels. - // - // Note that in most cases, labels have a value that varies during the - // lifetime of a process. Those labels are usually managed with a metric - // vector collector (like CounterVec, GaugeVec, UntypedVec). ConstLabels - // serve only special purposes. One is for the special case where the - // value of a label does not change during the lifetime of a process, - // e.g. if the revision of the running binary is put into a - // label. Another, more advanced purpose is if more than one Collector - // needs to collect Metrics with the same fully-qualified name. In that - // case, those Metrics must differ in the values of their - // ConstLabels. See the Collector examples. - // - // If the value of a label never changes (not even between binaries), - // that label most likely should not be a label at all (but part of the - // metric name). - ConstLabels Labels -} - -// BuildFQName joins the given three name components by "_". Empty name -// components are ignored. If the name parameter itself is empty, an empty -// string is returned, no matter what. Metric implementations included in this -// library use this function internally to generate the fully-qualified metric -// name from the name component in their Opts. Users of the library will only -// need this function if they implement their own Metric or instantiate a Desc -// (with NewDesc) directly. -func BuildFQName(namespace, subsystem, name string) string { - if name == "" { - return "" - } - switch { - case namespace != "" && subsystem != "": - return strings.Join([]string{namespace, subsystem, name}, "_") - case namespace != "": - return strings.Join([]string{namespace, name}, "_") - case subsystem != "": - return strings.Join([]string{subsystem, name}, "_") - } - return name -} - -// LabelPairSorter implements sort.Interface. It is used to sort a slice of -// dto.LabelPair pointers. This is useful for implementing the Write method of -// custom metrics. -type LabelPairSorter []*dto.LabelPair - -func (s LabelPairSorter) Len() int { - return len(s) -} - -func (s LabelPairSorter) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -func (s LabelPairSorter) Less(i, j int) bool { - return s[i].GetName() < s[j].GetName() -} - -type hashSorter []uint64 - -func (s hashSorter) Len() int { - return len(s) -} - -func (s hashSorter) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -func (s hashSorter) Less(i, j int) bool { - return s[i] < s[j] -} - -type invalidMetric struct { - desc *Desc - err error -} - -// NewInvalidMetric returns a metric whose Write method always returns the -// provided error. It is useful if a Collector finds itself unable to collect -// a metric and wishes to report an error to the registry. -func NewInvalidMetric(desc *Desc, err error) Metric { - return &invalidMetric{desc, err} -} - -func (m *invalidMetric) Desc() *Desc { return m.desc } - -func (m *invalidMetric) Write(*dto.Metric) error { return m.err } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/process_collector.go b/vendor/github.com/prometheus/client_golang/prometheus/process_collector.go deleted file mode 100644 index e31e62e..0000000 --- a/vendor/github.com/prometheus/client_golang/prometheus/process_collector.go +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright 2015 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. - -package prometheus - -import "github.com/prometheus/procfs" - -type processCollector struct { - pid int - collectFn func(chan<- Metric) - pidFn func() (int, error) - cpuTotal Counter - openFDs, maxFDs Gauge - vsize, rss Gauge - startTime Gauge -} - -// NewProcessCollector returns a collector which exports the current state of -// process metrics including cpu, memory and file descriptor usage as well as -// the process start time for the given process id under the given namespace. -func NewProcessCollector(pid int, namespace string) Collector { - return NewProcessCollectorPIDFn( - func() (int, error) { return pid, nil }, - namespace, - ) -} - -// NewProcessCollectorPIDFn returns a collector which exports the current state -// of process metrics including cpu, memory and file descriptor usage as well -// as the process start time under the given namespace. The given pidFn is -// called on each collect and is used to determine the process to export -// metrics for. -func NewProcessCollectorPIDFn( - pidFn func() (int, error), - namespace string, -) Collector { - c := processCollector{ - pidFn: pidFn, - collectFn: func(chan<- Metric) {}, - - cpuTotal: NewCounter(CounterOpts{ - Namespace: namespace, - Name: "process_cpu_seconds_total", - Help: "Total user and system CPU time spent in seconds.", - }), - openFDs: NewGauge(GaugeOpts{ - Namespace: namespace, - Name: "process_open_fds", - Help: "Number of open file descriptors.", - }), - maxFDs: NewGauge(GaugeOpts{ - Namespace: namespace, - Name: "process_max_fds", - Help: "Maximum number of open file descriptors.", - }), - vsize: NewGauge(GaugeOpts{ - Namespace: namespace, - Name: "process_virtual_memory_bytes", - Help: "Virtual memory size in bytes.", - }), - rss: NewGauge(GaugeOpts{ - Namespace: namespace, - Name: "process_resident_memory_bytes", - Help: "Resident memory size in bytes.", - }), - startTime: NewGauge(GaugeOpts{ - Namespace: namespace, - Name: "process_start_time_seconds", - Help: "Start time of the process since unix epoch in seconds.", - }), - } - - // Set up process metric collection if supported by the runtime. - if _, err := procfs.NewStat(); err == nil { - c.collectFn = c.processCollect - } - - return &c -} - -// Describe returns all descriptions of the collector. -func (c *processCollector) Describe(ch chan<- *Desc) { - ch <- c.cpuTotal.Desc() - ch <- c.openFDs.Desc() - ch <- c.maxFDs.Desc() - ch <- c.vsize.Desc() - ch <- c.rss.Desc() - ch <- c.startTime.Desc() -} - -// Collect returns the current state of all metrics of the collector. -func (c *processCollector) Collect(ch chan<- Metric) { - c.collectFn(ch) -} - -// TODO(ts): Bring back error reporting by reverting 7faf9e7 as soon as the -// client allows users to configure the error behavior. -func (c *processCollector) processCollect(ch chan<- Metric) { - pid, err := c.pidFn() - if err != nil { - return - } - - p, err := procfs.NewProc(pid) - if err != nil { - return - } - - if stat, err := p.NewStat(); err == nil { - c.cpuTotal.Set(stat.CPUTime()) - ch <- c.cpuTotal - c.vsize.Set(float64(stat.VirtualMemory())) - ch <- c.vsize - c.rss.Set(float64(stat.ResidentMemory())) - ch <- c.rss - - if startTime, err := stat.StartTime(); err == nil { - c.startTime.Set(startTime) - ch <- c.startTime - } - } - - if fds, err := p.FileDescriptorsLen(); err == nil { - c.openFDs.Set(float64(fds)) - ch <- c.openFDs - } - - if limits, err := p.NewLimits(); err == nil { - c.maxFDs.Set(float64(limits.OpenFiles)) - ch <- c.maxFDs - } -} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go deleted file mode 100644 index b6dd5a2..0000000 --- a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 2016 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. - -// Copyright (c) 2013, The Prometheus Authors -// All rights reserved. -// -// Use of this source code is governed by a BSD-style license that can be found -// in the LICENSE file. - -// Package promhttp contains functions to create http.Handler instances to -// expose Prometheus metrics via HTTP. In later versions of this package, it -// will also contain tooling to instrument instances of http.Handler and -// http.RoundTripper. -// -// promhttp.Handler acts on the prometheus.DefaultGatherer. With HandlerFor, -// you can create a handler for a custom registry or anything that implements -// the Gatherer interface. It also allows to create handlers that act -// differently on errors or allow to log errors. -package promhttp - -import ( - "bytes" - "compress/gzip" - "fmt" - "io" - "net/http" - "strings" - "sync" - - "github.com/prometheus/common/expfmt" - - "github.com/prometheus/client_golang/prometheus" -) - -const ( - contentTypeHeader = "Content-Type" - contentLengthHeader = "Content-Length" - contentEncodingHeader = "Content-Encoding" - acceptEncodingHeader = "Accept-Encoding" -) - -var bufPool sync.Pool - -func getBuf() *bytes.Buffer { - buf := bufPool.Get() - if buf == nil { - return &bytes.Buffer{} - } - return buf.(*bytes.Buffer) -} - -func giveBuf(buf *bytes.Buffer) { - buf.Reset() - bufPool.Put(buf) -} - -// Handler returns an HTTP handler for the prometheus.DefaultGatherer. The -// Handler uses the default HandlerOpts, i.e. report the first error as an HTTP -// error, no error logging, and compression if requested by the client. -// -// If you want to create a Handler for the DefaultGatherer with different -// HandlerOpts, create it with HandlerFor with prometheus.DefaultGatherer and -// your desired HandlerOpts. -func Handler() http.Handler { - return HandlerFor(prometheus.DefaultGatherer, HandlerOpts{}) -} - -// HandlerFor returns an http.Handler for the provided Gatherer. The behavior -// of the Handler is defined by the provided HandlerOpts. -func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - mfs, err := reg.Gather() - if err != nil { - if opts.ErrorLog != nil { - opts.ErrorLog.Println("error gathering metrics:", err) - } - switch opts.ErrorHandling { - case PanicOnError: - panic(err) - case ContinueOnError: - if len(mfs) == 0 { - http.Error(w, "No metrics gathered, last error:\n\n"+err.Error(), http.StatusInternalServerError) - return - } - case HTTPErrorOnError: - http.Error(w, "An error has occurred during metrics gathering:\n\n"+err.Error(), http.StatusInternalServerError) - return - } - } - - contentType := expfmt.Negotiate(req.Header) - buf := getBuf() - defer giveBuf(buf) - writer, encoding := decorateWriter(req, buf, opts.DisableCompression) - enc := expfmt.NewEncoder(writer, contentType) - var lastErr error - for _, mf := range mfs { - if err := enc.Encode(mf); err != nil { - lastErr = err - if opts.ErrorLog != nil { - opts.ErrorLog.Println("error encoding metric family:", err) - } - switch opts.ErrorHandling { - case PanicOnError: - panic(err) - case ContinueOnError: - // Handled later. - case HTTPErrorOnError: - http.Error(w, "An error has occurred during metrics encoding:\n\n"+err.Error(), http.StatusInternalServerError) - return - } - } - } - if closer, ok := writer.(io.Closer); ok { - closer.Close() - } - if lastErr != nil && buf.Len() == 0 { - http.Error(w, "No metrics encoded, last error:\n\n"+err.Error(), http.StatusInternalServerError) - return - } - header := w.Header() - header.Set(contentTypeHeader, string(contentType)) - header.Set(contentLengthHeader, fmt.Sprint(buf.Len())) - if encoding != "" { - header.Set(contentEncodingHeader, encoding) - } - w.Write(buf.Bytes()) - // TODO(beorn7): Consider streaming serving of metrics. - }) -} - -// HandlerErrorHandling defines how a Handler serving metrics will handle -// errors. -type HandlerErrorHandling int - -// These constants cause handlers serving metrics to behave as described if -// errors are encountered. -const ( - // Serve an HTTP status code 500 upon the first error - // encountered. Report the error message in the body. - HTTPErrorOnError HandlerErrorHandling = iota - // Ignore errors and try to serve as many metrics as possible. However, - // if no metrics can be served, serve an HTTP status code 500 and the - // last error message in the body. Only use this in deliberate "best - // effort" metrics collection scenarios. It is recommended to at least - // log errors (by providing an ErrorLog in HandlerOpts) to not mask - // errors completely. - ContinueOnError - // Panic upon the first error encountered (useful for "crash only" apps). - PanicOnError -) - -// Logger is the minimal interface HandlerOpts needs for logging. Note that -// log.Logger from the standard library implements this interface, and it is -// easy to implement by custom loggers, if they don't do so already anyway. -type Logger interface { - Println(v ...interface{}) -} - -// HandlerOpts specifies options how to serve metrics via an http.Handler. The -// zero value of HandlerOpts is a reasonable default. -type HandlerOpts struct { - // ErrorLog specifies an optional logger for errors collecting and - // serving metrics. If nil, errors are not logged at all. - ErrorLog Logger - // ErrorHandling defines how errors are handled. Note that errors are - // logged regardless of the configured ErrorHandling provided ErrorLog - // is not nil. - ErrorHandling HandlerErrorHandling - // If DisableCompression is true, the handler will never compress the - // response, even if requested by the client. - DisableCompression bool -} - -// decorateWriter wraps a writer to handle gzip compression if requested. It -// returns the decorated writer and the appropriate "Content-Encoding" header -// (which is empty if no compression is enabled). -func decorateWriter(request *http.Request, writer io.Writer, compressionDisabled bool) (io.Writer, string) { - if compressionDisabled { - return writer, "" - } - header := request.Header.Get(acceptEncodingHeader) - parts := strings.Split(header, ",") - for _, part := range parts { - part := strings.TrimSpace(part) - if part == "gzip" || strings.HasPrefix(part, "gzip;") { - return gzip.NewWriter(writer), "gzip" - } - } - return writer, "" -} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/registry.go b/vendor/github.com/prometheus/client_golang/prometheus/registry.go deleted file mode 100644 index 32a3986..0000000 --- a/vendor/github.com/prometheus/client_golang/prometheus/registry.go +++ /dev/null @@ -1,806 +0,0 @@ -// Copyright 2014 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. - -package prometheus - -import ( - "bytes" - "errors" - "fmt" - "os" - "sort" - "sync" - - "github.com/golang/protobuf/proto" - - dto "github.com/prometheus/client_model/go" -) - -const ( - // Capacity for the channel to collect metrics and descriptors. - capMetricChan = 1000 - capDescChan = 10 -) - -// DefaultRegisterer and DefaultGatherer are the implementations of the -// Registerer and Gatherer interface a number of convenience functions in this -// package act on. Initially, both variables point to the same Registry, which -// has a process collector (see NewProcessCollector) and a Go collector (see -// NewGoCollector) already registered. This approach to keep default instances -// as global state mirrors the approach of other packages in the Go standard -// library. Note that there are caveats. Change the variables with caution and -// only if you understand the consequences. Users who want to avoid global state -// altogether should not use the convenience function and act on custom -// instances instead. -var ( - defaultRegistry = NewRegistry() - DefaultRegisterer Registerer = defaultRegistry - DefaultGatherer Gatherer = defaultRegistry -) - -func init() { - MustRegister(NewProcessCollector(os.Getpid(), "")) - MustRegister(NewGoCollector()) -} - -// NewRegistry creates a new vanilla Registry without any Collectors -// pre-registered. -func NewRegistry() *Registry { - return &Registry{ - collectorsByID: map[uint64]Collector{}, - descIDs: map[uint64]struct{}{}, - dimHashesByName: map[string]uint64{}, - } -} - -// NewPedanticRegistry returns a registry that checks during collection if each -// collected Metric is consistent with its reported Desc, and if the Desc has -// actually been registered with the registry. -// -// Usually, a Registry will be happy as long as the union of all collected -// Metrics is consistent and valid even if some metrics are not consistent with -// their own Desc or a Desc provided by their registered Collector. Well-behaved -// Collectors and Metrics will only provide consistent Descs. This Registry is -// useful to test the implementation of Collectors and Metrics. -func NewPedanticRegistry() *Registry { - r := NewRegistry() - r.pedanticChecksEnabled = true - return r -} - -// Registerer is the interface for the part of a registry in charge of -// registering and unregistering. Users of custom registries should use -// Registerer as type for registration purposes (rather then the Registry type -// directly). In that way, they are free to use custom Registerer implementation -// (e.g. for testing purposes). -type Registerer interface { - // Register registers a new Collector to be included in metrics - // collection. It returns an error if the descriptors provided by the - // Collector are invalid or if they — in combination with descriptors of - // already registered Collectors — do not fulfill the consistency and - // uniqueness criteria described in the documentation of metric.Desc. - // - // If the provided Collector is equal to a Collector already registered - // (which includes the case of re-registering the same Collector), the - // returned error is an instance of AlreadyRegisteredError, which - // contains the previously registered Collector. - // - // It is in general not safe to register the same Collector multiple - // times concurrently. - Register(Collector) error - // MustRegister works like Register but registers any number of - // Collectors and panics upon the first registration that causes an - // error. - MustRegister(...Collector) - // Unregister unregisters the Collector that equals the Collector passed - // in as an argument. (Two Collectors are considered equal if their - // Describe method yields the same set of descriptors.) The function - // returns whether a Collector was unregistered. - // - // Note that even after unregistering, it will not be possible to - // register a new Collector that is inconsistent with the unregistered - // Collector, e.g. a Collector collecting metrics with the same name but - // a different help string. The rationale here is that the same registry - // instance must only collect consistent metrics throughout its - // lifetime. - Unregister(Collector) bool -} - -// Gatherer is the interface for the part of a registry in charge of gathering -// the collected metrics into a number of MetricFamilies. The Gatherer interface -// comes with the same general implication as described for the Registerer -// interface. -type Gatherer interface { - // Gather calls the Collect method of the registered Collectors and then - // gathers the collected metrics into a lexicographically sorted slice - // of MetricFamily protobufs. Even if an error occurs, Gather attempts - // to gather as many metrics as possible. Hence, if a non-nil error is - // returned, the returned MetricFamily slice could be nil (in case of a - // fatal error that prevented any meaningful metric collection) or - // contain a number of MetricFamily protobufs, some of which might be - // incomplete, and some might be missing altogether. The returned error - // (which might be a MultiError) explains the details. In scenarios - // where complete collection is critical, the returned MetricFamily - // protobufs should be disregarded if the returned error is non-nil. - Gather() ([]*dto.MetricFamily, error) -} - -// Register registers the provided Collector with the DefaultRegisterer. -// -// Register is a shortcut for DefaultRegisterer.Register(c). See there for more -// details. -func Register(c Collector) error { - return DefaultRegisterer.Register(c) -} - -// MustRegister registers the provided Collectors with the DefaultRegisterer and -// panics if any error occurs. -// -// MustRegister is a shortcut for DefaultRegisterer.MustRegister(cs...). See -// there for more details. -func MustRegister(cs ...Collector) { - DefaultRegisterer.MustRegister(cs...) -} - -// RegisterOrGet registers the provided Collector with the DefaultRegisterer and -// returns the Collector, unless an equal Collector was registered before, in -// which case that Collector is returned. -// -// Deprecated: RegisterOrGet is merely a convenience function for the -// implementation as described in the documentation for -// AlreadyRegisteredError. As the use case is relatively rare, this function -// will be removed in a future version of this package to clean up the -// namespace. -func RegisterOrGet(c Collector) (Collector, error) { - if err := Register(c); err != nil { - if are, ok := err.(AlreadyRegisteredError); ok { - return are.ExistingCollector, nil - } - return nil, err - } - return c, nil -} - -// MustRegisterOrGet behaves like RegisterOrGet but panics instead of returning -// an error. -// -// Deprecated: This is deprecated for the same reason RegisterOrGet is. See -// there for details. -func MustRegisterOrGet(c Collector) Collector { - c, err := RegisterOrGet(c) - if err != nil { - panic(err) - } - return c -} - -// Unregister removes the registration of the provided Collector from the -// DefaultRegisterer. -// -// Unregister is a shortcut for DefaultRegisterer.Unregister(c). See there for -// more details. -func Unregister(c Collector) bool { - return DefaultRegisterer.Unregister(c) -} - -// GathererFunc turns a function into a Gatherer. -type GathererFunc func() ([]*dto.MetricFamily, error) - -// Gather implements Gatherer. -func (gf GathererFunc) Gather() ([]*dto.MetricFamily, error) { - return gf() -} - -// SetMetricFamilyInjectionHook replaces the DefaultGatherer with one that -// gathers from the previous DefaultGatherers but then merges the MetricFamily -// protobufs returned from the provided hook function with the MetricFamily -// protobufs returned from the original DefaultGatherer. -// -// Deprecated: This function manipulates the DefaultGatherer variable. Consider -// the implications, i.e. don't do this concurrently with any uses of the -// DefaultGatherer. In the rare cases where you need to inject MetricFamily -// protobufs directly, it is recommended to use a custom Registry and combine it -// with a custom Gatherer using the Gatherers type (see -// there). SetMetricFamilyInjectionHook only exists for compatibility reasons -// with previous versions of this package. -func SetMetricFamilyInjectionHook(hook func() []*dto.MetricFamily) { - DefaultGatherer = Gatherers{ - DefaultGatherer, - GathererFunc(func() ([]*dto.MetricFamily, error) { return hook(), nil }), - } -} - -// AlreadyRegisteredError is returned by the Register method if the Collector to -// be registered has already been registered before, or a different Collector -// that collects the same metrics has been registered before. Registration fails -// in that case, but you can detect from the kind of error what has -// happened. The error contains fields for the existing Collector and the -// (rejected) new Collector that equals the existing one. This can be used to -// find out if an equal Collector has been registered before and switch over to -// using the old one, as demonstrated in the example. -type AlreadyRegisteredError struct { - ExistingCollector, NewCollector Collector -} - -func (err AlreadyRegisteredError) Error() string { - return "duplicate metrics collector registration attempted" -} - -// MultiError is a slice of errors implementing the error interface. It is used -// by a Gatherer to report multiple errors during MetricFamily gathering. -type MultiError []error - -func (errs MultiError) Error() string { - if len(errs) == 0 { - return "" - } - buf := &bytes.Buffer{} - fmt.Fprintf(buf, "%d error(s) occurred:", len(errs)) - for _, err := range errs { - fmt.Fprintf(buf, "\n* %s", err) - } - return buf.String() -} - -// MaybeUnwrap returns nil if len(errs) is 0. It returns the first and only -// contained error as error if len(errs is 1). In all other cases, it returns -// the MultiError directly. This is helpful for returning a MultiError in a way -// that only uses the MultiError if needed. -func (errs MultiError) MaybeUnwrap() error { - switch len(errs) { - case 0: - return nil - case 1: - return errs[0] - default: - return errs - } -} - -// Registry registers Prometheus collectors, collects their metrics, and gathers -// them into MetricFamilies for exposition. It implements both Registerer and -// Gatherer. The zero value is not usable. Create instances with NewRegistry or -// NewPedanticRegistry. -type Registry struct { - mtx sync.RWMutex - collectorsByID map[uint64]Collector // ID is a hash of the descIDs. - descIDs map[uint64]struct{} - dimHashesByName map[string]uint64 - pedanticChecksEnabled bool -} - -// Register implements Registerer. -func (r *Registry) Register(c Collector) error { - var ( - descChan = make(chan *Desc, capDescChan) - newDescIDs = map[uint64]struct{}{} - newDimHashesByName = map[string]uint64{} - collectorID uint64 // Just a sum of all desc IDs. - duplicateDescErr error - ) - go func() { - c.Describe(descChan) - close(descChan) - }() - r.mtx.Lock() - defer r.mtx.Unlock() - // Coduct various tests... - for desc := range descChan { - - // Is the descriptor valid at all? - if desc.err != nil { - return fmt.Errorf("descriptor %s is invalid: %s", desc, desc.err) - } - - // Is the descID unique? - // (In other words: Is the fqName + constLabel combination unique?) - if _, exists := r.descIDs[desc.id]; exists { - duplicateDescErr = fmt.Errorf("descriptor %s already exists with the same fully-qualified name and const label values", desc) - } - // If it is not a duplicate desc in this collector, add it to - // the collectorID. (We allow duplicate descs within the same - // collector, but their existence must be a no-op.) - if _, exists := newDescIDs[desc.id]; !exists { - newDescIDs[desc.id] = struct{}{} - collectorID += desc.id - } - - // Are all the label names and the help string consistent with - // previous descriptors of the same name? - // First check existing descriptors... - if dimHash, exists := r.dimHashesByName[desc.fqName]; exists { - if dimHash != desc.dimHash { - return fmt.Errorf("a previously registered descriptor with the same fully-qualified name as %s has different label names or a different help string", desc) - } - } else { - // ...then check the new descriptors already seen. - if dimHash, exists := newDimHashesByName[desc.fqName]; exists { - if dimHash != desc.dimHash { - return fmt.Errorf("descriptors reported by collector have inconsistent label names or help strings for the same fully-qualified name, offender is %s", desc) - } - } else { - newDimHashesByName[desc.fqName] = desc.dimHash - } - } - } - // Did anything happen at all? - if len(newDescIDs) == 0 { - return errors.New("collector has no descriptors") - } - if existing, exists := r.collectorsByID[collectorID]; exists { - return AlreadyRegisteredError{ - ExistingCollector: existing, - NewCollector: c, - } - } - // If the collectorID is new, but at least one of the descs existed - // before, we are in trouble. - if duplicateDescErr != nil { - return duplicateDescErr - } - - // Only after all tests have passed, actually register. - r.collectorsByID[collectorID] = c - for hash := range newDescIDs { - r.descIDs[hash] = struct{}{} - } - for name, dimHash := range newDimHashesByName { - r.dimHashesByName[name] = dimHash - } - return nil -} - -// Unregister implements Registerer. -func (r *Registry) Unregister(c Collector) bool { - var ( - descChan = make(chan *Desc, capDescChan) - descIDs = map[uint64]struct{}{} - collectorID uint64 // Just a sum of the desc IDs. - ) - go func() { - c.Describe(descChan) - close(descChan) - }() - for desc := range descChan { - if _, exists := descIDs[desc.id]; !exists { - collectorID += desc.id - descIDs[desc.id] = struct{}{} - } - } - - r.mtx.RLock() - if _, exists := r.collectorsByID[collectorID]; !exists { - r.mtx.RUnlock() - return false - } - r.mtx.RUnlock() - - r.mtx.Lock() - defer r.mtx.Unlock() - - delete(r.collectorsByID, collectorID) - for id := range descIDs { - delete(r.descIDs, id) - } - // dimHashesByName is left untouched as those must be consistent - // throughout the lifetime of a program. - return true -} - -// MustRegister implements Registerer. -func (r *Registry) MustRegister(cs ...Collector) { - for _, c := range cs { - if err := r.Register(c); err != nil { - panic(err) - } - } -} - -// Gather implements Gatherer. -func (r *Registry) Gather() ([]*dto.MetricFamily, error) { - var ( - metricChan = make(chan Metric, capMetricChan) - metricHashes = map[uint64]struct{}{} - dimHashes = map[string]uint64{} - wg sync.WaitGroup - errs MultiError // The collected errors to return in the end. - registeredDescIDs map[uint64]struct{} // Only used for pedantic checks - ) - - r.mtx.RLock() - metricFamiliesByName := make(map[string]*dto.MetricFamily, len(r.dimHashesByName)) - - // Scatter. - // (Collectors could be complex and slow, so we call them all at once.) - wg.Add(len(r.collectorsByID)) - go func() { - wg.Wait() - close(metricChan) - }() - for _, collector := range r.collectorsByID { - go func(collector Collector) { - defer wg.Done() - collector.Collect(metricChan) - }(collector) - } - - // In case pedantic checks are enabled, we have to copy the map before - // giving up the RLock. - if r.pedanticChecksEnabled { - registeredDescIDs = make(map[uint64]struct{}, len(r.descIDs)) - for id := range r.descIDs { - registeredDescIDs[id] = struct{}{} - } - } - - r.mtx.RUnlock() - - // Drain metricChan in case of premature return. - defer func() { - for _ = range metricChan { - } - }() - - // Gather. - for metric := range metricChan { - // This could be done concurrently, too, but it required locking - // of metricFamiliesByName (and of metricHashes if checks are - // enabled). Most likely not worth it. - desc := metric.Desc() - dtoMetric := &dto.Metric{} - if err := metric.Write(dtoMetric); err != nil { - errs = append(errs, fmt.Errorf( - "error collecting metric %v: %s", desc, err, - )) - continue - } - metricFamily, ok := metricFamiliesByName[desc.fqName] - if ok { - if metricFamily.GetHelp() != desc.help { - errs = append(errs, fmt.Errorf( - "collected metric %s %s has help %q but should have %q", - desc.fqName, dtoMetric, desc.help, metricFamily.GetHelp(), - )) - continue - } - // TODO(beorn7): Simplify switch once Desc has type. - switch metricFamily.GetType() { - case dto.MetricType_COUNTER: - if dtoMetric.Counter == nil { - errs = append(errs, fmt.Errorf( - "collected metric %s %s should be a Counter", - desc.fqName, dtoMetric, - )) - continue - } - case dto.MetricType_GAUGE: - if dtoMetric.Gauge == nil { - errs = append(errs, fmt.Errorf( - "collected metric %s %s should be a Gauge", - desc.fqName, dtoMetric, - )) - continue - } - case dto.MetricType_SUMMARY: - if dtoMetric.Summary == nil { - errs = append(errs, fmt.Errorf( - "collected metric %s %s should be a Summary", - desc.fqName, dtoMetric, - )) - continue - } - case dto.MetricType_UNTYPED: - if dtoMetric.Untyped == nil { - errs = append(errs, fmt.Errorf( - "collected metric %s %s should be Untyped", - desc.fqName, dtoMetric, - )) - continue - } - case dto.MetricType_HISTOGRAM: - if dtoMetric.Histogram == nil { - errs = append(errs, fmt.Errorf( - "collected metric %s %s should be a Histogram", - desc.fqName, dtoMetric, - )) - continue - } - default: - panic("encountered MetricFamily with invalid type") - } - } else { - metricFamily = &dto.MetricFamily{} - metricFamily.Name = proto.String(desc.fqName) - metricFamily.Help = proto.String(desc.help) - // TODO(beorn7): Simplify switch once Desc has type. - switch { - case dtoMetric.Gauge != nil: - metricFamily.Type = dto.MetricType_GAUGE.Enum() - case dtoMetric.Counter != nil: - metricFamily.Type = dto.MetricType_COUNTER.Enum() - case dtoMetric.Summary != nil: - metricFamily.Type = dto.MetricType_SUMMARY.Enum() - case dtoMetric.Untyped != nil: - metricFamily.Type = dto.MetricType_UNTYPED.Enum() - case dtoMetric.Histogram != nil: - metricFamily.Type = dto.MetricType_HISTOGRAM.Enum() - default: - errs = append(errs, fmt.Errorf( - "empty metric collected: %s", dtoMetric, - )) - continue - } - metricFamiliesByName[desc.fqName] = metricFamily - } - if err := checkMetricConsistency(metricFamily, dtoMetric, metricHashes, dimHashes); err != nil { - errs = append(errs, err) - continue - } - if r.pedanticChecksEnabled { - // Is the desc registered at all? - if _, exist := registeredDescIDs[desc.id]; !exist { - errs = append(errs, fmt.Errorf( - "collected metric %s %s with unregistered descriptor %s", - metricFamily.GetName(), dtoMetric, desc, - )) - continue - } - if err := checkDescConsistency(metricFamily, dtoMetric, desc); err != nil { - errs = append(errs, err) - continue - } - } - metricFamily.Metric = append(metricFamily.Metric, dtoMetric) - } - return normalizeMetricFamilies(metricFamiliesByName), errs.MaybeUnwrap() -} - -// Gatherers is a slice of Gatherer instances that implements the Gatherer -// interface itself. Its Gather method calls Gather on all Gatherers in the -// slice in order and returns the merged results. Errors returned from the -// Gather calles are all returned in a flattened MultiError. Duplicate and -// inconsistent Metrics are skipped (first occurrence in slice order wins) and -// reported in the returned error. -// -// Gatherers can be used to merge the Gather results from multiple -// Registries. It also provides a way to directly inject existing MetricFamily -// protobufs into the gathering by creating a custom Gatherer with a Gather -// method that simply returns the existing MetricFamily protobufs. Note that no -// registration is involved (in contrast to Collector registration), so -// obviously registration-time checks cannot happen. Any inconsistencies between -// the gathered MetricFamilies are reported as errors by the Gather method, and -// inconsistent Metrics are dropped. Invalid parts of the MetricFamilies -// (e.g. syntactically invalid metric or label names) will go undetected. -type Gatherers []Gatherer - -// Gather implements Gatherer. -func (gs Gatherers) Gather() ([]*dto.MetricFamily, error) { - var ( - metricFamiliesByName = map[string]*dto.MetricFamily{} - metricHashes = map[uint64]struct{}{} - dimHashes = map[string]uint64{} - errs MultiError // The collected errors to return in the end. - ) - - for i, g := range gs { - mfs, err := g.Gather() - if err != nil { - if multiErr, ok := err.(MultiError); ok { - for _, err := range multiErr { - errs = append(errs, fmt.Errorf("[from Gatherer #%d] %s", i+1, err)) - } - } else { - errs = append(errs, fmt.Errorf("[from Gatherer #%d] %s", i+1, err)) - } - } - for _, mf := range mfs { - existingMF, exists := metricFamiliesByName[mf.GetName()] - if exists { - if existingMF.GetHelp() != mf.GetHelp() { - errs = append(errs, fmt.Errorf( - "gathered metric family %s has help %q but should have %q", - mf.GetName(), mf.GetHelp(), existingMF.GetHelp(), - )) - continue - } - if existingMF.GetType() != mf.GetType() { - errs = append(errs, fmt.Errorf( - "gathered metric family %s has type %s but should have %s", - mf.GetName(), mf.GetType(), existingMF.GetType(), - )) - continue - } - } else { - existingMF = &dto.MetricFamily{} - existingMF.Name = mf.Name - existingMF.Help = mf.Help - existingMF.Type = mf.Type - metricFamiliesByName[mf.GetName()] = existingMF - } - for _, m := range mf.Metric { - if err := checkMetricConsistency(existingMF, m, metricHashes, dimHashes); err != nil { - errs = append(errs, err) - continue - } - existingMF.Metric = append(existingMF.Metric, m) - } - } - } - return normalizeMetricFamilies(metricFamiliesByName), errs.MaybeUnwrap() -} - -// metricSorter is a sortable slice of *dto.Metric. -type metricSorter []*dto.Metric - -func (s metricSorter) Len() int { - return len(s) -} - -func (s metricSorter) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -func (s metricSorter) Less(i, j int) bool { - if len(s[i].Label) != len(s[j].Label) { - // This should not happen. The metrics are - // inconsistent. However, we have to deal with the fact, as - // people might use custom collectors or metric family injection - // to create inconsistent metrics. So let's simply compare the - // number of labels in this case. That will still yield - // reproducible sorting. - return len(s[i].Label) < len(s[j].Label) - } - for n, lp := range s[i].Label { - vi := lp.GetValue() - vj := s[j].Label[n].GetValue() - if vi != vj { - return vi < vj - } - } - - // We should never arrive here. Multiple metrics with the same - // label set in the same scrape will lead to undefined ingestion - // behavior. However, as above, we have to provide stable sorting - // here, even for inconsistent metrics. So sort equal metrics - // by their timestamp, with missing timestamps (implying "now") - // coming last. - if s[i].TimestampMs == nil { - return false - } - if s[j].TimestampMs == nil { - return true - } - return s[i].GetTimestampMs() < s[j].GetTimestampMs() -} - -// normalizeMetricFamilies returns a MetricFamily slice whith empty -// MetricFamilies pruned and the remaining MetricFamilies sorted by name within -// the slice, with the contained Metrics sorted within each MetricFamily. -func normalizeMetricFamilies(metricFamiliesByName map[string]*dto.MetricFamily) []*dto.MetricFamily { - for _, mf := range metricFamiliesByName { - sort.Sort(metricSorter(mf.Metric)) - } - names := make([]string, 0, len(metricFamiliesByName)) - for name, mf := range metricFamiliesByName { - if len(mf.Metric) > 0 { - names = append(names, name) - } - } - sort.Strings(names) - result := make([]*dto.MetricFamily, 0, len(names)) - for _, name := range names { - result = append(result, metricFamiliesByName[name]) - } - return result -} - -// checkMetricConsistency checks if the provided Metric is consistent with the -// provided MetricFamily. It also hashed the Metric labels and the MetricFamily -// name. If the resulting hash is alread in the provided metricHashes, an error -// is returned. If not, it is added to metricHashes. The provided dimHashes maps -// MetricFamily names to their dimHash (hashed sorted label names). If dimHashes -// doesn't yet contain a hash for the provided MetricFamily, it is -// added. Otherwise, an error is returned if the existing dimHashes in not equal -// the calculated dimHash. -func checkMetricConsistency( - metricFamily *dto.MetricFamily, - dtoMetric *dto.Metric, - metricHashes map[uint64]struct{}, - dimHashes map[string]uint64, -) error { - // Type consistency with metric family. - if metricFamily.GetType() == dto.MetricType_GAUGE && dtoMetric.Gauge == nil || - metricFamily.GetType() == dto.MetricType_COUNTER && dtoMetric.Counter == nil || - metricFamily.GetType() == dto.MetricType_SUMMARY && dtoMetric.Summary == nil || - metricFamily.GetType() == dto.MetricType_HISTOGRAM && dtoMetric.Histogram == nil || - metricFamily.GetType() == dto.MetricType_UNTYPED && dtoMetric.Untyped == nil { - return fmt.Errorf( - "collected metric %s %s is not a %s", - metricFamily.GetName(), dtoMetric, metricFamily.GetType(), - ) - } - - // Is the metric unique (i.e. no other metric with the same name and the same label values)? - h := hashNew() - h = hashAdd(h, metricFamily.GetName()) - h = hashAddByte(h, separatorByte) - dh := hashNew() - // Make sure label pairs are sorted. We depend on it for the consistency - // check. - sort.Sort(LabelPairSorter(dtoMetric.Label)) - for _, lp := range dtoMetric.Label { - h = hashAdd(h, lp.GetValue()) - h = hashAddByte(h, separatorByte) - dh = hashAdd(dh, lp.GetName()) - dh = hashAddByte(dh, separatorByte) - } - if _, exists := metricHashes[h]; exists { - return fmt.Errorf( - "collected metric %s %s was collected before with the same name and label values", - metricFamily.GetName(), dtoMetric, - ) - } - if dimHash, ok := dimHashes[metricFamily.GetName()]; ok { - if dimHash != dh { - return fmt.Errorf( - "collected metric %s %s has label dimensions inconsistent with previously collected metrics in the same metric family", - metricFamily.GetName(), dtoMetric, - ) - } - } else { - dimHashes[metricFamily.GetName()] = dh - } - metricHashes[h] = struct{}{} - return nil -} - -func checkDescConsistency( - metricFamily *dto.MetricFamily, - dtoMetric *dto.Metric, - desc *Desc, -) error { - // Desc help consistency with metric family help. - if metricFamily.GetHelp() != desc.help { - return fmt.Errorf( - "collected metric %s %s has help %q but should have %q", - metricFamily.GetName(), dtoMetric, metricFamily.GetHelp(), desc.help, - ) - } - - // Is the desc consistent with the content of the metric? - lpsFromDesc := make([]*dto.LabelPair, 0, len(dtoMetric.Label)) - lpsFromDesc = append(lpsFromDesc, desc.constLabelPairs...) - for _, l := range desc.variableLabels { - lpsFromDesc = append(lpsFromDesc, &dto.LabelPair{ - Name: proto.String(l), - }) - } - if len(lpsFromDesc) != len(dtoMetric.Label) { - return fmt.Errorf( - "labels in collected metric %s %s are inconsistent with descriptor %s", - metricFamily.GetName(), dtoMetric, desc, - ) - } - sort.Sort(LabelPairSorter(lpsFromDesc)) - for i, lpFromDesc := range lpsFromDesc { - lpFromMetric := dtoMetric.Label[i] - if lpFromDesc.GetName() != lpFromMetric.GetName() || - lpFromDesc.Value != nil && lpFromDesc.GetValue() != lpFromMetric.GetValue() { - return fmt.Errorf( - "labels in collected metric %s %s are inconsistent with descriptor %s", - metricFamily.GetName(), dtoMetric, desc, - ) - } - } - return nil -} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/summary.go b/vendor/github.com/prometheus/client_golang/prometheus/summary.go deleted file mode 100644 index bce05bf..0000000 --- a/vendor/github.com/prometheus/client_golang/prometheus/summary.go +++ /dev/null @@ -1,534 +0,0 @@ -// Copyright 2014 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. - -package prometheus - -import ( - "fmt" - "math" - "sort" - "sync" - "time" - - "github.com/beorn7/perks/quantile" - "github.com/golang/protobuf/proto" - - dto "github.com/prometheus/client_model/go" -) - -// quantileLabel is used for the label that defines the quantile in a -// summary. -const quantileLabel = "quantile" - -// A Summary captures individual observations from an event or sample stream and -// summarizes them in a manner similar to traditional summary statistics: 1. sum -// of observations, 2. observation count, 3. rank estimations. -// -// A typical use-case is the observation of request latencies. By default, a -// Summary provides the median, the 90th and the 99th percentile of the latency -// as rank estimations. -// -// Note that the rank estimations cannot be aggregated in a meaningful way with -// the Prometheus query language (i.e. you cannot average or add them). If you -// need aggregatable quantiles (e.g. you want the 99th percentile latency of all -// queries served across all instances of a service), consider the Histogram -// metric type. See the Prometheus documentation for more details. -// -// To create Summary instances, use NewSummary. -type Summary interface { - Metric - Collector - - // Observe adds a single observation to the summary. - Observe(float64) -} - -// DefObjectives are the default Summary quantile values. -var ( - DefObjectives = map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001} - - errQuantileLabelNotAllowed = fmt.Errorf( - "%q is not allowed as label name in summaries", quantileLabel, - ) -) - -// Default values for SummaryOpts. -const ( - // DefMaxAge is the default duration for which observations stay - // relevant. - DefMaxAge time.Duration = 10 * time.Minute - // DefAgeBuckets is the default number of buckets used to calculate the - // age of observations. - DefAgeBuckets = 5 - // DefBufCap is the standard buffer size for collecting Summary observations. - DefBufCap = 500 -) - -// SummaryOpts bundles the options for creating a Summary metric. It is -// mandatory to set Name and Help to a non-empty string. All other fields are -// optional and can safely be left at their zero value. -type SummaryOpts struct { - // Namespace, Subsystem, and Name are components of the fully-qualified - // name of the Summary (created by joining these components with - // "_"). Only Name is mandatory, the others merely help structuring the - // name. Note that the fully-qualified name of the Summary must be a - // valid Prometheus metric name. - Namespace string - Subsystem string - Name string - - // Help provides information about this Summary. Mandatory! - // - // Metrics with the same fully-qualified name must have the same Help - // string. - Help string - - // ConstLabels are used to attach fixed labels to this - // Summary. Summaries with the same fully-qualified name must have the - // same label names in their ConstLabels. - // - // Note that in most cases, labels have a value that varies during the - // lifetime of a process. Those labels are usually managed with a - // SummaryVec. ConstLabels serve only special purposes. One is for the - // special case where the value of a label does not change during the - // lifetime of a process, e.g. if the revision of the running binary is - // put into a label. Another, more advanced purpose is if more than one - // Collector needs to collect Summaries with the same fully-qualified - // name. In that case, those Summaries must differ in the values of - // their ConstLabels. See the Collector examples. - // - // If the value of a label never changes (not even between binaries), - // that label most likely should not be a label at all (but part of the - // metric name). - ConstLabels Labels - - // Objectives defines the quantile rank estimates with their respective - // absolute error. If Objectives[q] = e, then the value reported - // for q will be the φ-quantile value for some φ between q-e and q+e. - // The default value is DefObjectives. - Objectives map[float64]float64 - - // MaxAge defines the duration for which an observation stays relevant - // for the summary. Must be positive. The default value is DefMaxAge. - MaxAge time.Duration - - // AgeBuckets is the number of buckets used to exclude observations that - // are older than MaxAge from the summary. A higher number has a - // resource penalty, so only increase it if the higher resolution is - // really required. For very high observation rates, you might want to - // reduce the number of age buckets. With only one age bucket, you will - // effectively see a complete reset of the summary each time MaxAge has - // passed. The default value is DefAgeBuckets. - AgeBuckets uint32 - - // BufCap defines the default sample stream buffer size. The default - // value of DefBufCap should suffice for most uses. If there is a need - // to increase the value, a multiple of 500 is recommended (because that - // is the internal buffer size of the underlying package - // "github.com/bmizerany/perks/quantile"). - BufCap uint32 -} - -// Great fuck-up with the sliding-window decay algorithm... The Merge method of -// perk/quantile is actually not working as advertised - and it might be -// unfixable, as the underlying algorithm is apparently not capable of merging -// summaries in the first place. To avoid using Merge, we are currently adding -// observations to _each_ age bucket, i.e. the effort to add a sample is -// essentially multiplied by the number of age buckets. When rotating age -// buckets, we empty the previous head stream. On scrape time, we simply take -// the quantiles from the head stream (no merging required). Result: More effort -// on observation time, less effort on scrape time, which is exactly the -// opposite of what we try to accomplish, but at least the results are correct. -// -// The quite elegant previous contraption to merge the age buckets efficiently -// on scrape time (see code up commit 6b9530d72ea715f0ba612c0120e6e09fbf1d49d0) -// can't be used anymore. - -// NewSummary creates a new Summary based on the provided SummaryOpts. -func NewSummary(opts SummaryOpts) Summary { - return newSummary( - NewDesc( - BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), - opts.Help, - nil, - opts.ConstLabels, - ), - opts, - ) -} - -func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary { - if len(desc.variableLabels) != len(labelValues) { - panic(errInconsistentCardinality) - } - - for _, n := range desc.variableLabels { - if n == quantileLabel { - panic(errQuantileLabelNotAllowed) - } - } - for _, lp := range desc.constLabelPairs { - if lp.GetName() == quantileLabel { - panic(errQuantileLabelNotAllowed) - } - } - - if len(opts.Objectives) == 0 { - opts.Objectives = DefObjectives - } - - if opts.MaxAge < 0 { - panic(fmt.Errorf("illegal max age MaxAge=%v", opts.MaxAge)) - } - if opts.MaxAge == 0 { - opts.MaxAge = DefMaxAge - } - - if opts.AgeBuckets == 0 { - opts.AgeBuckets = DefAgeBuckets - } - - if opts.BufCap == 0 { - opts.BufCap = DefBufCap - } - - s := &summary{ - desc: desc, - - objectives: opts.Objectives, - sortedObjectives: make([]float64, 0, len(opts.Objectives)), - - labelPairs: makeLabelPairs(desc, labelValues), - - hotBuf: make([]float64, 0, opts.BufCap), - coldBuf: make([]float64, 0, opts.BufCap), - streamDuration: opts.MaxAge / time.Duration(opts.AgeBuckets), - } - s.headStreamExpTime = time.Now().Add(s.streamDuration) - s.hotBufExpTime = s.headStreamExpTime - - for i := uint32(0); i < opts.AgeBuckets; i++ { - s.streams = append(s.streams, s.newStream()) - } - s.headStream = s.streams[0] - - for qu := range s.objectives { - s.sortedObjectives = append(s.sortedObjectives, qu) - } - sort.Float64s(s.sortedObjectives) - - s.init(s) // Init self-collection. - return s -} - -type summary struct { - selfCollector - - bufMtx sync.Mutex // Protects hotBuf and hotBufExpTime. - mtx sync.Mutex // Protects every other moving part. - // Lock bufMtx before mtx if both are needed. - - desc *Desc - - objectives map[float64]float64 - sortedObjectives []float64 - - labelPairs []*dto.LabelPair - - sum float64 - cnt uint64 - - hotBuf, coldBuf []float64 - - streams []*quantile.Stream - streamDuration time.Duration - headStream *quantile.Stream - headStreamIdx int - headStreamExpTime, hotBufExpTime time.Time -} - -func (s *summary) Desc() *Desc { - return s.desc -} - -func (s *summary) Observe(v float64) { - s.bufMtx.Lock() - defer s.bufMtx.Unlock() - - now := time.Now() - if now.After(s.hotBufExpTime) { - s.asyncFlush(now) - } - s.hotBuf = append(s.hotBuf, v) - if len(s.hotBuf) == cap(s.hotBuf) { - s.asyncFlush(now) - } -} - -func (s *summary) Write(out *dto.Metric) error { - sum := &dto.Summary{} - qs := make([]*dto.Quantile, 0, len(s.objectives)) - - s.bufMtx.Lock() - s.mtx.Lock() - // Swap bufs even if hotBuf is empty to set new hotBufExpTime. - s.swapBufs(time.Now()) - s.bufMtx.Unlock() - - s.flushColdBuf() - sum.SampleCount = proto.Uint64(s.cnt) - sum.SampleSum = proto.Float64(s.sum) - - for _, rank := range s.sortedObjectives { - var q float64 - if s.headStream.Count() == 0 { - q = math.NaN() - } else { - q = s.headStream.Query(rank) - } - qs = append(qs, &dto.Quantile{ - Quantile: proto.Float64(rank), - Value: proto.Float64(q), - }) - } - - s.mtx.Unlock() - - if len(qs) > 0 { - sort.Sort(quantSort(qs)) - } - sum.Quantile = qs - - out.Summary = sum - out.Label = s.labelPairs - return nil -} - -func (s *summary) newStream() *quantile.Stream { - return quantile.NewTargeted(s.objectives) -} - -// asyncFlush needs bufMtx locked. -func (s *summary) asyncFlush(now time.Time) { - s.mtx.Lock() - s.swapBufs(now) - - // Unblock the original goroutine that was responsible for the mutation - // that triggered the compaction. But hold onto the global non-buffer - // state mutex until the operation finishes. - go func() { - s.flushColdBuf() - s.mtx.Unlock() - }() -} - -// rotateStreams needs mtx AND bufMtx locked. -func (s *summary) maybeRotateStreams() { - for !s.hotBufExpTime.Equal(s.headStreamExpTime) { - s.headStream.Reset() - s.headStreamIdx++ - if s.headStreamIdx >= len(s.streams) { - s.headStreamIdx = 0 - } - s.headStream = s.streams[s.headStreamIdx] - s.headStreamExpTime = s.headStreamExpTime.Add(s.streamDuration) - } -} - -// flushColdBuf needs mtx locked. -func (s *summary) flushColdBuf() { - for _, v := range s.coldBuf { - for _, stream := range s.streams { - stream.Insert(v) - } - s.cnt++ - s.sum += v - } - s.coldBuf = s.coldBuf[0:0] - s.maybeRotateStreams() -} - -// swapBufs needs mtx AND bufMtx locked, coldBuf must be empty. -func (s *summary) swapBufs(now time.Time) { - if len(s.coldBuf) != 0 { - panic("coldBuf is not empty") - } - s.hotBuf, s.coldBuf = s.coldBuf, s.hotBuf - // hotBuf is now empty and gets new expiration set. - for now.After(s.hotBufExpTime) { - s.hotBufExpTime = s.hotBufExpTime.Add(s.streamDuration) - } -} - -type quantSort []*dto.Quantile - -func (s quantSort) Len() int { - return len(s) -} - -func (s quantSort) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -func (s quantSort) Less(i, j int) bool { - return s[i].GetQuantile() < s[j].GetQuantile() -} - -// SummaryVec is a Collector that bundles a set of Summaries that all share the -// same Desc, but have different values for their variable labels. This is used -// if you want to count the same thing partitioned by various dimensions -// (e.g. HTTP request latencies, partitioned by status code and method). Create -// instances with NewSummaryVec. -type SummaryVec struct { - *MetricVec -} - -// NewSummaryVec creates a new SummaryVec based on the provided SummaryOpts and -// partitioned by the given label names. At least one label name must be -// provided. -func NewSummaryVec(opts SummaryOpts, labelNames []string) *SummaryVec { - desc := NewDesc( - BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), - opts.Help, - labelNames, - opts.ConstLabels, - ) - return &SummaryVec{ - MetricVec: newMetricVec(desc, func(lvs ...string) Metric { - return newSummary(desc, opts, lvs...) - }), - } -} - -// GetMetricWithLabelValues replaces the method of the same name in -// MetricVec. The difference is that this method returns a Summary and not a -// Metric so that no type conversion is required. -func (m *SummaryVec) GetMetricWithLabelValues(lvs ...string) (Summary, error) { - metric, err := m.MetricVec.GetMetricWithLabelValues(lvs...) - if metric != nil { - return metric.(Summary), err - } - return nil, err -} - -// GetMetricWith replaces the method of the same name in MetricVec. The -// difference is that this method returns a Summary and not a Metric so that no -// type conversion is required. -func (m *SummaryVec) GetMetricWith(labels Labels) (Summary, error) { - metric, err := m.MetricVec.GetMetricWith(labels) - if metric != nil { - return metric.(Summary), err - } - return nil, err -} - -// WithLabelValues works as GetMetricWithLabelValues, but panics where -// GetMetricWithLabelValues would have returned an error. By not returning an -// error, WithLabelValues allows shortcuts like -// myVec.WithLabelValues("404", "GET").Observe(42.21) -func (m *SummaryVec) WithLabelValues(lvs ...string) Summary { - return m.MetricVec.WithLabelValues(lvs...).(Summary) -} - -// With works as GetMetricWith, but panics where GetMetricWithLabels would have -// returned an error. By not returning an error, With allows shortcuts like -// myVec.With(Labels{"code": "404", "method": "GET"}).Observe(42.21) -func (m *SummaryVec) With(labels Labels) Summary { - return m.MetricVec.With(labels).(Summary) -} - -type constSummary struct { - desc *Desc - count uint64 - sum float64 - quantiles map[float64]float64 - labelPairs []*dto.LabelPair -} - -func (s *constSummary) Desc() *Desc { - return s.desc -} - -func (s *constSummary) Write(out *dto.Metric) error { - sum := &dto.Summary{} - qs := make([]*dto.Quantile, 0, len(s.quantiles)) - - sum.SampleCount = proto.Uint64(s.count) - sum.SampleSum = proto.Float64(s.sum) - - for rank, q := range s.quantiles { - qs = append(qs, &dto.Quantile{ - Quantile: proto.Float64(rank), - Value: proto.Float64(q), - }) - } - - if len(qs) > 0 { - sort.Sort(quantSort(qs)) - } - sum.Quantile = qs - - out.Summary = sum - out.Label = s.labelPairs - - return nil -} - -// NewConstSummary returns a metric representing a Prometheus summary with fixed -// values for the count, sum, and quantiles. As those parameters cannot be -// changed, the returned value does not implement the Summary interface (but -// only the Metric interface). Users of this package will not have much use for -// it in regular operations. However, when implementing custom Collectors, it is -// useful as a throw-away metric that is generated on the fly to send it to -// Prometheus in the Collect method. -// -// quantiles maps ranks to quantile values. For example, a median latency of -// 0.23s and a 99th percentile latency of 0.56s would be expressed as: -// map[float64]float64{0.5: 0.23, 0.99: 0.56} -// -// NewConstSummary returns an error if the length of labelValues is not -// consistent with the variable labels in Desc. -func NewConstSummary( - desc *Desc, - count uint64, - sum float64, - quantiles map[float64]float64, - labelValues ...string, -) (Metric, error) { - if len(desc.variableLabels) != len(labelValues) { - return nil, errInconsistentCardinality - } - return &constSummary{ - desc: desc, - count: count, - sum: sum, - quantiles: quantiles, - labelPairs: makeLabelPairs(desc, labelValues), - }, nil -} - -// MustNewConstSummary is a version of NewConstSummary that panics where -// NewConstMetric would have returned an error. -func MustNewConstSummary( - desc *Desc, - count uint64, - sum float64, - quantiles map[float64]float64, - labelValues ...string, -) Metric { - m, err := NewConstSummary(desc, count, sum, quantiles, labelValues...) - if err != nil { - panic(err) - } - return m -} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/untyped.go b/vendor/github.com/prometheus/client_golang/prometheus/untyped.go deleted file mode 100644 index 5faf7e6..0000000 --- a/vendor/github.com/prometheus/client_golang/prometheus/untyped.go +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright 2014 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. - -package prometheus - -// Untyped is a Metric that represents a single numerical value that can -// arbitrarily go up and down. -// -// An Untyped metric works the same as a Gauge. The only difference is that to -// no type information is implied. -// -// To create Untyped instances, use NewUntyped. -type Untyped interface { - Metric - Collector - - // Set sets the Untyped metric to an arbitrary value. - Set(float64) - // Inc increments the Untyped metric by 1. - Inc() - // Dec decrements the Untyped metric by 1. - Dec() - // Add adds the given value to the Untyped metric. (The value can be - // negative, resulting in a decrease.) - Add(float64) - // Sub subtracts the given value from the Untyped metric. (The value can - // be negative, resulting in an increase.) - Sub(float64) -} - -// UntypedOpts is an alias for Opts. See there for doc comments. -type UntypedOpts Opts - -// NewUntyped creates a new Untyped metric from the provided UntypedOpts. -func NewUntyped(opts UntypedOpts) Untyped { - return newValue(NewDesc( - BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), - opts.Help, - nil, - opts.ConstLabels, - ), UntypedValue, 0) -} - -// UntypedVec is a Collector that bundles a set of Untyped metrics that all -// share the same Desc, but have different values for their variable -// labels. This is used if you want to count the same thing partitioned by -// various dimensions. Create instances with NewUntypedVec. -type UntypedVec struct { - *MetricVec -} - -// NewUntypedVec creates a new UntypedVec based on the provided UntypedOpts and -// partitioned by the given label names. At least one label name must be -// provided. -func NewUntypedVec(opts UntypedOpts, labelNames []string) *UntypedVec { - desc := NewDesc( - BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), - opts.Help, - labelNames, - opts.ConstLabels, - ) - return &UntypedVec{ - MetricVec: newMetricVec(desc, func(lvs ...string) Metric { - return newValue(desc, UntypedValue, 0, lvs...) - }), - } -} - -// GetMetricWithLabelValues replaces the method of the same name in -// MetricVec. The difference is that this method returns an Untyped and not a -// Metric so that no type conversion is required. -func (m *UntypedVec) GetMetricWithLabelValues(lvs ...string) (Untyped, error) { - metric, err := m.MetricVec.GetMetricWithLabelValues(lvs...) - if metric != nil { - return metric.(Untyped), err - } - return nil, err -} - -// GetMetricWith replaces the method of the same name in MetricVec. The -// difference is that this method returns an Untyped and not a Metric so that no -// type conversion is required. -func (m *UntypedVec) GetMetricWith(labels Labels) (Untyped, error) { - metric, err := m.MetricVec.GetMetricWith(labels) - if metric != nil { - return metric.(Untyped), err - } - return nil, err -} - -// WithLabelValues works as GetMetricWithLabelValues, but panics where -// GetMetricWithLabelValues would have returned an error. By not returning an -// error, WithLabelValues allows shortcuts like -// myVec.WithLabelValues("404", "GET").Add(42) -func (m *UntypedVec) WithLabelValues(lvs ...string) Untyped { - return m.MetricVec.WithLabelValues(lvs...).(Untyped) -} - -// With works as GetMetricWith, but panics where GetMetricWithLabels would have -// returned an error. By not returning an error, With allows shortcuts like -// myVec.With(Labels{"code": "404", "method": "GET"}).Add(42) -func (m *UntypedVec) With(labels Labels) Untyped { - return m.MetricVec.With(labels).(Untyped) -} - -// UntypedFunc is an Untyped whose value is determined at collect time by -// calling a provided function. -// -// To create UntypedFunc instances, use NewUntypedFunc. -type UntypedFunc interface { - Metric - Collector -} - -// NewUntypedFunc creates a new UntypedFunc based on the provided -// UntypedOpts. The value reported is determined by calling the given function -// from within the Write method. Take into account that metric collection may -// happen concurrently. If that results in concurrent calls to Write, like in -// the case where an UntypedFunc is directly registered with Prometheus, the -// provided function must be concurrency-safe. -func NewUntypedFunc(opts UntypedOpts, function func() float64) UntypedFunc { - return newValueFunc(NewDesc( - BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), - opts.Help, - nil, - opts.ConstLabels, - ), UntypedValue, function) -} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/value.go b/vendor/github.com/prometheus/client_golang/prometheus/value.go deleted file mode 100644 index a944c37..0000000 --- a/vendor/github.com/prometheus/client_golang/prometheus/value.go +++ /dev/null @@ -1,234 +0,0 @@ -// Copyright 2014 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. - -package prometheus - -import ( - "errors" - "fmt" - "math" - "sort" - "sync/atomic" - - dto "github.com/prometheus/client_model/go" - - "github.com/golang/protobuf/proto" -) - -// ValueType is an enumeration of metric types that represent a simple value. -type ValueType int - -// Possible values for the ValueType enum. -const ( - _ ValueType = iota - CounterValue - GaugeValue - UntypedValue -) - -var errInconsistentCardinality = errors.New("inconsistent label cardinality") - -// value is a generic metric for simple values. It implements Metric, Collector, -// Counter, Gauge, and Untyped. Its effective type is determined by -// ValueType. This is a low-level building block used by the library to back the -// implementations of Counter, Gauge, and Untyped. -type value struct { - // valBits containst the bits of the represented float64 value. It has - // to go first in the struct to guarantee alignment for atomic - // operations. http://golang.org/pkg/sync/atomic/#pkg-note-BUG - valBits uint64 - - selfCollector - - desc *Desc - valType ValueType - labelPairs []*dto.LabelPair -} - -// newValue returns a newly allocated value with the given Desc, ValueType, -// sample value and label values. It panics if the number of label -// values is different from the number of variable labels in Desc. -func newValue(desc *Desc, valueType ValueType, val float64, labelValues ...string) *value { - if len(labelValues) != len(desc.variableLabels) { - panic(errInconsistentCardinality) - } - result := &value{ - desc: desc, - valType: valueType, - valBits: math.Float64bits(val), - labelPairs: makeLabelPairs(desc, labelValues), - } - result.init(result) - return result -} - -func (v *value) Desc() *Desc { - return v.desc -} - -func (v *value) Set(val float64) { - atomic.StoreUint64(&v.valBits, math.Float64bits(val)) -} - -func (v *value) Inc() { - v.Add(1) -} - -func (v *value) Dec() { - v.Add(-1) -} - -func (v *value) Add(val float64) { - for { - oldBits := atomic.LoadUint64(&v.valBits) - newBits := math.Float64bits(math.Float64frombits(oldBits) + val) - if atomic.CompareAndSwapUint64(&v.valBits, oldBits, newBits) { - return - } - } -} - -func (v *value) Sub(val float64) { - v.Add(val * -1) -} - -func (v *value) Write(out *dto.Metric) error { - val := math.Float64frombits(atomic.LoadUint64(&v.valBits)) - return populateMetric(v.valType, val, v.labelPairs, out) -} - -// valueFunc is a generic metric for simple values retrieved on collect time -// from a function. It implements Metric and Collector. Its effective type is -// determined by ValueType. This is a low-level building block used by the -// library to back the implementations of CounterFunc, GaugeFunc, and -// UntypedFunc. -type valueFunc struct { - selfCollector - - desc *Desc - valType ValueType - function func() float64 - labelPairs []*dto.LabelPair -} - -// newValueFunc returns a newly allocated valueFunc with the given Desc and -// ValueType. The value reported is determined by calling the given function -// from within the Write method. Take into account that metric collection may -// happen concurrently. If that results in concurrent calls to Write, like in -// the case where a valueFunc is directly registered with Prometheus, the -// provided function must be concurrency-safe. -func newValueFunc(desc *Desc, valueType ValueType, function func() float64) *valueFunc { - result := &valueFunc{ - desc: desc, - valType: valueType, - function: function, - labelPairs: makeLabelPairs(desc, nil), - } - result.init(result) - return result -} - -func (v *valueFunc) Desc() *Desc { - return v.desc -} - -func (v *valueFunc) Write(out *dto.Metric) error { - return populateMetric(v.valType, v.function(), v.labelPairs, out) -} - -// NewConstMetric returns a metric with one fixed value that cannot be -// changed. Users of this package will not have much use for it in regular -// operations. However, when implementing custom Collectors, it is useful as a -// throw-away metric that is generated on the fly to send it to Prometheus in -// the Collect method. NewConstMetric returns an error if the length of -// labelValues is not consistent with the variable labels in Desc. -func NewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues ...string) (Metric, error) { - if len(desc.variableLabels) != len(labelValues) { - return nil, errInconsistentCardinality - } - return &constMetric{ - desc: desc, - valType: valueType, - val: value, - labelPairs: makeLabelPairs(desc, labelValues), - }, nil -} - -// MustNewConstMetric is a version of NewConstMetric that panics where -// NewConstMetric would have returned an error. -func MustNewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues ...string) Metric { - m, err := NewConstMetric(desc, valueType, value, labelValues...) - if err != nil { - panic(err) - } - return m -} - -type constMetric struct { - desc *Desc - valType ValueType - val float64 - labelPairs []*dto.LabelPair -} - -func (m *constMetric) Desc() *Desc { - return m.desc -} - -func (m *constMetric) Write(out *dto.Metric) error { - return populateMetric(m.valType, m.val, m.labelPairs, out) -} - -func populateMetric( - t ValueType, - v float64, - labelPairs []*dto.LabelPair, - m *dto.Metric, -) error { - m.Label = labelPairs - switch t { - case CounterValue: - m.Counter = &dto.Counter{Value: proto.Float64(v)} - case GaugeValue: - m.Gauge = &dto.Gauge{Value: proto.Float64(v)} - case UntypedValue: - m.Untyped = &dto.Untyped{Value: proto.Float64(v)} - default: - return fmt.Errorf("encountered unknown type %v", t) - } - return nil -} - -func makeLabelPairs(desc *Desc, labelValues []string) []*dto.LabelPair { - totalLen := len(desc.variableLabels) + len(desc.constLabelPairs) - if totalLen == 0 { - // Super fast path. - return nil - } - if len(desc.variableLabels) == 0 { - // Moderately fast path. - return desc.constLabelPairs - } - labelPairs := make([]*dto.LabelPair, 0, totalLen) - for i, n := range desc.variableLabels { - labelPairs = append(labelPairs, &dto.LabelPair{ - Name: proto.String(n), - Value: proto.String(labelValues[i]), - }) - } - for _, lp := range desc.constLabelPairs { - labelPairs = append(labelPairs, lp) - } - sort.Sort(LabelPairSorter(labelPairs)) - return labelPairs -} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/vec.go b/vendor/github.com/prometheus/client_golang/prometheus/vec.go deleted file mode 100644 index 7f3eef9..0000000 --- a/vendor/github.com/prometheus/client_golang/prometheus/vec.go +++ /dev/null @@ -1,404 +0,0 @@ -// Copyright 2014 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. - -package prometheus - -import ( - "fmt" - "sync" - - "github.com/prometheus/common/model" -) - -// MetricVec is a Collector to bundle metrics of the same name that -// differ in their label values. MetricVec is usually not used directly but as a -// building block for implementations of vectors of a given metric -// type. GaugeVec, CounterVec, SummaryVec, and UntypedVec are examples already -// provided in this package. -type MetricVec struct { - mtx sync.RWMutex // Protects the children. - children map[uint64][]metricWithLabelValues - desc *Desc - - newMetric func(labelValues ...string) Metric - hashAdd func(h uint64, s string) uint64 // replace hash function for testing collision handling - hashAddByte func(h uint64, b byte) uint64 -} - -// newMetricVec returns an initialized MetricVec. The concrete value is -// returned for embedding into another struct. -func newMetricVec(desc *Desc, newMetric func(lvs ...string) Metric) *MetricVec { - return &MetricVec{ - children: map[uint64][]metricWithLabelValues{}, - desc: desc, - newMetric: newMetric, - hashAdd: hashAdd, - hashAddByte: hashAddByte, - } -} - -// metricWithLabelValues provides the metric and its label values for -// disambiguation on hash collision. -type metricWithLabelValues struct { - values []string - metric Metric -} - -// Describe implements Collector. The length of the returned slice -// is always one. -func (m *MetricVec) Describe(ch chan<- *Desc) { - ch <- m.desc -} - -// Collect implements Collector. -func (m *MetricVec) Collect(ch chan<- Metric) { - m.mtx.RLock() - defer m.mtx.RUnlock() - - for _, metrics := range m.children { - for _, metric := range metrics { - ch <- metric.metric - } - } -} - -// GetMetricWithLabelValues returns the Metric for the given slice of label -// values (same order as the VariableLabels in Desc). If that combination of -// label values is accessed for the first time, a new Metric is created. -// -// It is possible to call this method without using the returned Metric to only -// create the new Metric but leave it at its start value (e.g. a Summary or -// Histogram without any observations). See also the SummaryVec example. -// -// Keeping the Metric for later use is possible (and should be considered if -// performance is critical), but keep in mind that Reset, DeleteLabelValues and -// Delete can be used to delete the Metric from the MetricVec. In that case, the -// Metric will still exist, but it will not be exported anymore, even if a -// Metric with the same label values is created later. See also the CounterVec -// example. -// -// An error is returned if the number of label values is not the same as the -// number of VariableLabels in Desc. -// -// Note that for more than one label value, this method is prone to mistakes -// caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as -// an alternative to avoid that type of mistake. For higher label numbers, the -// latter has a much more readable (albeit more verbose) syntax, but it comes -// with a performance overhead (for creating and processing the Labels map). -// See also the GaugeVec example. -func (m *MetricVec) GetMetricWithLabelValues(lvs ...string) (Metric, error) { - h, err := m.hashLabelValues(lvs) - if err != nil { - return nil, err - } - - return m.getOrCreateMetricWithLabelValues(h, lvs), nil -} - -// GetMetricWith returns the Metric for the given Labels map (the label names -// must match those of the VariableLabels in Desc). If that label map is -// accessed for the first time, a new Metric is created. Implications of -// creating a Metric without using it and keeping the Metric for later use are -// the same as for GetMetricWithLabelValues. -// -// An error is returned if the number and names of the Labels are inconsistent -// with those of the VariableLabels in Desc. -// -// This method is used for the same purpose as -// GetMetricWithLabelValues(...string). See there for pros and cons of the two -// methods. -func (m *MetricVec) GetMetricWith(labels Labels) (Metric, error) { - h, err := m.hashLabels(labels) - if err != nil { - return nil, err - } - - return m.getOrCreateMetricWithLabels(h, labels), nil -} - -// WithLabelValues works as GetMetricWithLabelValues, but panics if an error -// occurs. The method allows neat syntax like: -// httpReqs.WithLabelValues("404", "POST").Inc() -func (m *MetricVec) WithLabelValues(lvs ...string) Metric { - metric, err := m.GetMetricWithLabelValues(lvs...) - if err != nil { - panic(err) - } - return metric -} - -// With works as GetMetricWith, but panics if an error occurs. The method allows -// neat syntax like: -// httpReqs.With(Labels{"status":"404", "method":"POST"}).Inc() -func (m *MetricVec) With(labels Labels) Metric { - metric, err := m.GetMetricWith(labels) - if err != nil { - panic(err) - } - return metric -} - -// DeleteLabelValues removes the metric where the variable labels are the same -// as those passed in as labels (same order as the VariableLabels in Desc). It -// returns true if a metric was deleted. -// -// It is not an error if the number of label values is not the same as the -// number of VariableLabels in Desc. However, such inconsistent label count can -// never match an actual Metric, so the method will always return false in that -// case. -// -// Note that for more than one label value, this method is prone to mistakes -// caused by an incorrect order of arguments. Consider Delete(Labels) as an -// alternative to avoid that type of mistake. For higher label numbers, the -// latter has a much more readable (albeit more verbose) syntax, but it comes -// with a performance overhead (for creating and processing the Labels map). -// See also the CounterVec example. -func (m *MetricVec) DeleteLabelValues(lvs ...string) bool { - m.mtx.Lock() - defer m.mtx.Unlock() - - h, err := m.hashLabelValues(lvs) - if err != nil { - return false - } - return m.deleteByHashWithLabelValues(h, lvs) -} - -// Delete deletes the metric where the variable labels are the same as those -// passed in as labels. It returns true if a metric was deleted. -// -// It is not an error if the number and names of the Labels are inconsistent -// with those of the VariableLabels in the Desc of the MetricVec. However, such -// inconsistent Labels can never match an actual Metric, so the method will -// always return false in that case. -// -// This method is used for the same purpose as DeleteLabelValues(...string). See -// there for pros and cons of the two methods. -func (m *MetricVec) Delete(labels Labels) bool { - m.mtx.Lock() - defer m.mtx.Unlock() - - h, err := m.hashLabels(labels) - if err != nil { - return false - } - - return m.deleteByHashWithLabels(h, labels) -} - -// deleteByHashWithLabelValues removes the metric from the hash bucket h. If -// there are multiple matches in the bucket, use lvs to select a metric and -// remove only that metric. -func (m *MetricVec) deleteByHashWithLabelValues(h uint64, lvs []string) bool { - metrics, ok := m.children[h] - if !ok { - return false - } - - i := m.findMetricWithLabelValues(metrics, lvs) - if i >= len(metrics) { - return false - } - - if len(metrics) > 1 { - m.children[h] = append(metrics[:i], metrics[i+1:]...) - } else { - delete(m.children, h) - } - return true -} - -// deleteByHashWithLabels removes the metric from the hash bucket h. If there -// are multiple matches in the bucket, use lvs to select a metric and remove -// only that metric. -func (m *MetricVec) deleteByHashWithLabels(h uint64, labels Labels) bool { - metrics, ok := m.children[h] - if !ok { - return false - } - i := m.findMetricWithLabels(metrics, labels) - if i >= len(metrics) { - return false - } - - if len(metrics) > 1 { - m.children[h] = append(metrics[:i], metrics[i+1:]...) - } else { - delete(m.children, h) - } - return true -} - -// Reset deletes all metrics in this vector. -func (m *MetricVec) Reset() { - m.mtx.Lock() - defer m.mtx.Unlock() - - for h := range m.children { - delete(m.children, h) - } -} - -func (m *MetricVec) hashLabelValues(vals []string) (uint64, error) { - if len(vals) != len(m.desc.variableLabels) { - return 0, errInconsistentCardinality - } - h := hashNew() - for _, val := range vals { - h = m.hashAdd(h, val) - h = m.hashAddByte(h, model.SeparatorByte) - } - return h, nil -} - -func (m *MetricVec) hashLabels(labels Labels) (uint64, error) { - if len(labels) != len(m.desc.variableLabels) { - return 0, errInconsistentCardinality - } - h := hashNew() - for _, label := range m.desc.variableLabels { - val, ok := labels[label] - if !ok { - return 0, fmt.Errorf("label name %q missing in label map", label) - } - h = m.hashAdd(h, val) - h = m.hashAddByte(h, model.SeparatorByte) - } - return h, nil -} - -// getOrCreateMetricWithLabelValues retrieves the metric by hash and label value -// or creates it and returns the new one. -// -// This function holds the mutex. -func (m *MetricVec) getOrCreateMetricWithLabelValues(hash uint64, lvs []string) Metric { - m.mtx.RLock() - metric, ok := m.getMetricWithLabelValues(hash, lvs) - m.mtx.RUnlock() - if ok { - return metric - } - - m.mtx.Lock() - defer m.mtx.Unlock() - metric, ok = m.getMetricWithLabelValues(hash, lvs) - if !ok { - // Copy to avoid allocation in case wo don't go down this code path. - copiedLVs := make([]string, len(lvs)) - copy(copiedLVs, lvs) - metric = m.newMetric(copiedLVs...) - m.children[hash] = append(m.children[hash], metricWithLabelValues{values: copiedLVs, metric: metric}) - } - return metric -} - -// getOrCreateMetricWithLabelValues retrieves the metric by hash and label value -// or creates it and returns the new one. -// -// This function holds the mutex. -func (m *MetricVec) getOrCreateMetricWithLabels(hash uint64, labels Labels) Metric { - m.mtx.RLock() - metric, ok := m.getMetricWithLabels(hash, labels) - m.mtx.RUnlock() - if ok { - return metric - } - - m.mtx.Lock() - defer m.mtx.Unlock() - metric, ok = m.getMetricWithLabels(hash, labels) - if !ok { - lvs := m.extractLabelValues(labels) - metric = m.newMetric(lvs...) - m.children[hash] = append(m.children[hash], metricWithLabelValues{values: lvs, metric: metric}) - } - return metric -} - -// getMetricWithLabelValues gets a metric while handling possible collisions in -// the hash space. Must be called while holding read mutex. -func (m *MetricVec) getMetricWithLabelValues(h uint64, lvs []string) (Metric, bool) { - metrics, ok := m.children[h] - if ok { - if i := m.findMetricWithLabelValues(metrics, lvs); i < len(metrics) { - return metrics[i].metric, true - } - } - return nil, false -} - -// getMetricWithLabels gets a metric while handling possible collisions in -// the hash space. Must be called while holding read mutex. -func (m *MetricVec) getMetricWithLabels(h uint64, labels Labels) (Metric, bool) { - metrics, ok := m.children[h] - if ok { - if i := m.findMetricWithLabels(metrics, labels); i < len(metrics) { - return metrics[i].metric, true - } - } - return nil, false -} - -// findMetricWithLabelValues returns the index of the matching metric or -// len(metrics) if not found. -func (m *MetricVec) findMetricWithLabelValues(metrics []metricWithLabelValues, lvs []string) int { - for i, metric := range metrics { - if m.matchLabelValues(metric.values, lvs) { - return i - } - } - return len(metrics) -} - -// findMetricWithLabels returns the index of the matching metric or len(metrics) -// if not found. -func (m *MetricVec) findMetricWithLabels(metrics []metricWithLabelValues, labels Labels) int { - for i, metric := range metrics { - if m.matchLabels(metric.values, labels) { - return i - } - } - return len(metrics) -} - -func (m *MetricVec) matchLabelValues(values []string, lvs []string) bool { - if len(values) != len(lvs) { - return false - } - for i, v := range values { - if v != lvs[i] { - return false - } - } - return true -} - -func (m *MetricVec) matchLabels(values []string, labels Labels) bool { - if len(labels) != len(values) { - return false - } - for i, k := range m.desc.variableLabels { - if values[i] != labels[k] { - return false - } - } - return true -} - -func (m *MetricVec) extractLabelValues(labels Labels) []string { - labelValues := make([]string, len(labels)) - for i, k := range m.desc.variableLabels { - labelValues[i] = labels[k] - } - return labelValues -} diff --git a/vendor/github.com/prometheus/client_model/LICENSE b/vendor/github.com/prometheus/client_model/LICENSE deleted file mode 100644 index 261eeb9..0000000 --- a/vendor/github.com/prometheus/client_model/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. diff --git a/vendor/github.com/prometheus/client_model/NOTICE b/vendor/github.com/prometheus/client_model/NOTICE deleted file mode 100644 index 20110e4..0000000 --- a/vendor/github.com/prometheus/client_model/NOTICE +++ /dev/null @@ -1,5 +0,0 @@ -Data model artifacts for Prometheus. -Copyright 2012-2015 The Prometheus Authors - -This product includes software developed at -SoundCloud Ltd. (http://soundcloud.com/). diff --git a/vendor/github.com/prometheus/client_model/go/metrics.pb.go b/vendor/github.com/prometheus/client_model/go/metrics.pb.go deleted file mode 100644 index b065f86..0000000 --- a/vendor/github.com/prometheus/client_model/go/metrics.pb.go +++ /dev/null @@ -1,364 +0,0 @@ -// Code generated by protoc-gen-go. -// source: metrics.proto -// DO NOT EDIT! - -/* -Package io_prometheus_client is a generated protocol buffer package. - -It is generated from these files: - metrics.proto - -It has these top-level messages: - LabelPair - Gauge - Counter - Quantile - Summary - Untyped - Histogram - Bucket - Metric - MetricFamily -*/ -package io_prometheus_client - -import proto "github.com/golang/protobuf/proto" -import math "math" - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = math.Inf - -type MetricType int32 - -const ( - MetricType_COUNTER MetricType = 0 - MetricType_GAUGE MetricType = 1 - MetricType_SUMMARY MetricType = 2 - MetricType_UNTYPED MetricType = 3 - MetricType_HISTOGRAM MetricType = 4 -) - -var MetricType_name = map[int32]string{ - 0: "COUNTER", - 1: "GAUGE", - 2: "SUMMARY", - 3: "UNTYPED", - 4: "HISTOGRAM", -} -var MetricType_value = map[string]int32{ - "COUNTER": 0, - "GAUGE": 1, - "SUMMARY": 2, - "UNTYPED": 3, - "HISTOGRAM": 4, -} - -func (x MetricType) Enum() *MetricType { - p := new(MetricType) - *p = x - return p -} -func (x MetricType) String() string { - return proto.EnumName(MetricType_name, int32(x)) -} -func (x *MetricType) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(MetricType_value, data, "MetricType") - if err != nil { - return err - } - *x = MetricType(value) - return nil -} - -type LabelPair struct { - Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - Value *string `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *LabelPair) Reset() { *m = LabelPair{} } -func (m *LabelPair) String() string { return proto.CompactTextString(m) } -func (*LabelPair) ProtoMessage() {} - -func (m *LabelPair) GetName() string { - if m != nil && m.Name != nil { - return *m.Name - } - return "" -} - -func (m *LabelPair) GetValue() string { - if m != nil && m.Value != nil { - return *m.Value - } - return "" -} - -type Gauge struct { - Value *float64 `protobuf:"fixed64,1,opt,name=value" json:"value,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Gauge) Reset() { *m = Gauge{} } -func (m *Gauge) String() string { return proto.CompactTextString(m) } -func (*Gauge) ProtoMessage() {} - -func (m *Gauge) GetValue() float64 { - if m != nil && m.Value != nil { - return *m.Value - } - return 0 -} - -type Counter struct { - Value *float64 `protobuf:"fixed64,1,opt,name=value" json:"value,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Counter) Reset() { *m = Counter{} } -func (m *Counter) String() string { return proto.CompactTextString(m) } -func (*Counter) ProtoMessage() {} - -func (m *Counter) GetValue() float64 { - if m != nil && m.Value != nil { - return *m.Value - } - return 0 -} - -type Quantile struct { - Quantile *float64 `protobuf:"fixed64,1,opt,name=quantile" json:"quantile,omitempty"` - Value *float64 `protobuf:"fixed64,2,opt,name=value" json:"value,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Quantile) Reset() { *m = Quantile{} } -func (m *Quantile) String() string { return proto.CompactTextString(m) } -func (*Quantile) ProtoMessage() {} - -func (m *Quantile) GetQuantile() float64 { - if m != nil && m.Quantile != nil { - return *m.Quantile - } - return 0 -} - -func (m *Quantile) GetValue() float64 { - if m != nil && m.Value != nil { - return *m.Value - } - return 0 -} - -type Summary struct { - SampleCount *uint64 `protobuf:"varint,1,opt,name=sample_count" json:"sample_count,omitempty"` - SampleSum *float64 `protobuf:"fixed64,2,opt,name=sample_sum" json:"sample_sum,omitempty"` - Quantile []*Quantile `protobuf:"bytes,3,rep,name=quantile" json:"quantile,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Summary) Reset() { *m = Summary{} } -func (m *Summary) String() string { return proto.CompactTextString(m) } -func (*Summary) ProtoMessage() {} - -func (m *Summary) GetSampleCount() uint64 { - if m != nil && m.SampleCount != nil { - return *m.SampleCount - } - return 0 -} - -func (m *Summary) GetSampleSum() float64 { - if m != nil && m.SampleSum != nil { - return *m.SampleSum - } - return 0 -} - -func (m *Summary) GetQuantile() []*Quantile { - if m != nil { - return m.Quantile - } - return nil -} - -type Untyped struct { - Value *float64 `protobuf:"fixed64,1,opt,name=value" json:"value,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Untyped) Reset() { *m = Untyped{} } -func (m *Untyped) String() string { return proto.CompactTextString(m) } -func (*Untyped) ProtoMessage() {} - -func (m *Untyped) GetValue() float64 { - if m != nil && m.Value != nil { - return *m.Value - } - return 0 -} - -type Histogram struct { - SampleCount *uint64 `protobuf:"varint,1,opt,name=sample_count" json:"sample_count,omitempty"` - SampleSum *float64 `protobuf:"fixed64,2,opt,name=sample_sum" json:"sample_sum,omitempty"` - Bucket []*Bucket `protobuf:"bytes,3,rep,name=bucket" json:"bucket,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Histogram) Reset() { *m = Histogram{} } -func (m *Histogram) String() string { return proto.CompactTextString(m) } -func (*Histogram) ProtoMessage() {} - -func (m *Histogram) GetSampleCount() uint64 { - if m != nil && m.SampleCount != nil { - return *m.SampleCount - } - return 0 -} - -func (m *Histogram) GetSampleSum() float64 { - if m != nil && m.SampleSum != nil { - return *m.SampleSum - } - return 0 -} - -func (m *Histogram) GetBucket() []*Bucket { - if m != nil { - return m.Bucket - } - return nil -} - -type Bucket struct { - CumulativeCount *uint64 `protobuf:"varint,1,opt,name=cumulative_count" json:"cumulative_count,omitempty"` - UpperBound *float64 `protobuf:"fixed64,2,opt,name=upper_bound" json:"upper_bound,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Bucket) Reset() { *m = Bucket{} } -func (m *Bucket) String() string { return proto.CompactTextString(m) } -func (*Bucket) ProtoMessage() {} - -func (m *Bucket) GetCumulativeCount() uint64 { - if m != nil && m.CumulativeCount != nil { - return *m.CumulativeCount - } - return 0 -} - -func (m *Bucket) GetUpperBound() float64 { - if m != nil && m.UpperBound != nil { - return *m.UpperBound - } - return 0 -} - -type Metric struct { - Label []*LabelPair `protobuf:"bytes,1,rep,name=label" json:"label,omitempty"` - Gauge *Gauge `protobuf:"bytes,2,opt,name=gauge" json:"gauge,omitempty"` - Counter *Counter `protobuf:"bytes,3,opt,name=counter" json:"counter,omitempty"` - Summary *Summary `protobuf:"bytes,4,opt,name=summary" json:"summary,omitempty"` - Untyped *Untyped `protobuf:"bytes,5,opt,name=untyped" json:"untyped,omitempty"` - Histogram *Histogram `protobuf:"bytes,7,opt,name=histogram" json:"histogram,omitempty"` - TimestampMs *int64 `protobuf:"varint,6,opt,name=timestamp_ms" json:"timestamp_ms,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Metric) Reset() { *m = Metric{} } -func (m *Metric) String() string { return proto.CompactTextString(m) } -func (*Metric) ProtoMessage() {} - -func (m *Metric) GetLabel() []*LabelPair { - if m != nil { - return m.Label - } - return nil -} - -func (m *Metric) GetGauge() *Gauge { - if m != nil { - return m.Gauge - } - return nil -} - -func (m *Metric) GetCounter() *Counter { - if m != nil { - return m.Counter - } - return nil -} - -func (m *Metric) GetSummary() *Summary { - if m != nil { - return m.Summary - } - return nil -} - -func (m *Metric) GetUntyped() *Untyped { - if m != nil { - return m.Untyped - } - return nil -} - -func (m *Metric) GetHistogram() *Histogram { - if m != nil { - return m.Histogram - } - return nil -} - -func (m *Metric) GetTimestampMs() int64 { - if m != nil && m.TimestampMs != nil { - return *m.TimestampMs - } - return 0 -} - -type MetricFamily struct { - Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - Help *string `protobuf:"bytes,2,opt,name=help" json:"help,omitempty"` - Type *MetricType `protobuf:"varint,3,opt,name=type,enum=io.prometheus.client.MetricType" json:"type,omitempty"` - Metric []*Metric `protobuf:"bytes,4,rep,name=metric" json:"metric,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *MetricFamily) Reset() { *m = MetricFamily{} } -func (m *MetricFamily) String() string { return proto.CompactTextString(m) } -func (*MetricFamily) ProtoMessage() {} - -func (m *MetricFamily) GetName() string { - if m != nil && m.Name != nil { - return *m.Name - } - return "" -} - -func (m *MetricFamily) GetHelp() string { - if m != nil && m.Help != nil { - return *m.Help - } - return "" -} - -func (m *MetricFamily) GetType() MetricType { - if m != nil && m.Type != nil { - return *m.Type - } - return MetricType_COUNTER -} - -func (m *MetricFamily) GetMetric() []*Metric { - if m != nil { - return m.Metric - } - return nil -} - -func init() { - proto.RegisterEnum("io.prometheus.client.MetricType", MetricType_name, MetricType_value) -} diff --git a/vendor/github.com/prometheus/client_model/ruby/LICENSE b/vendor/github.com/prometheus/client_model/ruby/LICENSE deleted file mode 100644 index 11069ed..0000000 --- a/vendor/github.com/prometheus/client_model/ruby/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -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. diff --git a/vendor/github.com/prometheus/common/LICENSE b/vendor/github.com/prometheus/common/LICENSE deleted file mode 100644 index 261eeb9..0000000 --- a/vendor/github.com/prometheus/common/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. diff --git a/vendor/github.com/prometheus/common/NOTICE b/vendor/github.com/prometheus/common/NOTICE deleted file mode 100644 index 636a2c1..0000000 --- a/vendor/github.com/prometheus/common/NOTICE +++ /dev/null @@ -1,5 +0,0 @@ -Common libraries shared by Prometheus Go components. -Copyright 2015 The Prometheus Authors - -This product includes software developed at -SoundCloud Ltd. (http://soundcloud.com/). diff --git a/vendor/github.com/prometheus/common/expfmt/decode.go b/vendor/github.com/prometheus/common/expfmt/decode.go deleted file mode 100644 index a7a42d5..0000000 --- a/vendor/github.com/prometheus/common/expfmt/decode.go +++ /dev/null @@ -1,429 +0,0 @@ -// Copyright 2015 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. - -package expfmt - -import ( - "fmt" - "io" - "math" - "mime" - "net/http" - - dto "github.com/prometheus/client_model/go" - - "github.com/matttproud/golang_protobuf_extensions/pbutil" - "github.com/prometheus/common/model" -) - -// Decoder types decode an input stream into metric families. -type Decoder interface { - Decode(*dto.MetricFamily) error -} - -// DecodeOptions contains options used by the Decoder and in sample extraction. -type DecodeOptions struct { - // Timestamp is added to each value from the stream that has no explicit timestamp set. - Timestamp model.Time -} - -// ResponseFormat extracts the correct format from a HTTP response header. -// If no matching format can be found FormatUnknown is returned. -func ResponseFormat(h http.Header) Format { - ct := h.Get(hdrContentType) - - mediatype, params, err := mime.ParseMediaType(ct) - if err != nil { - return FmtUnknown - } - - const textType = "text/plain" - - switch mediatype { - case ProtoType: - if p, ok := params["proto"]; ok && p != ProtoProtocol { - return FmtUnknown - } - if e, ok := params["encoding"]; ok && e != "delimited" { - return FmtUnknown - } - return FmtProtoDelim - - case textType: - if v, ok := params["version"]; ok && v != TextVersion { - return FmtUnknown - } - return FmtText - } - - return FmtUnknown -} - -// NewDecoder returns a new decoder based on the given input format. -// If the input format does not imply otherwise, a text format decoder is returned. -func NewDecoder(r io.Reader, format Format) Decoder { - switch format { - case FmtProtoDelim: - return &protoDecoder{r: r} - } - return &textDecoder{r: r} -} - -// protoDecoder implements the Decoder interface for protocol buffers. -type protoDecoder struct { - r io.Reader -} - -// Decode implements the Decoder interface. -func (d *protoDecoder) Decode(v *dto.MetricFamily) error { - _, err := pbutil.ReadDelimited(d.r, v) - if err != nil { - return err - } - if !model.IsValidMetricName(model.LabelValue(v.GetName())) { - return fmt.Errorf("invalid metric name %q", v.GetName()) - } - for _, m := range v.GetMetric() { - if m == nil { - continue - } - for _, l := range m.GetLabel() { - if l == nil { - continue - } - if !model.LabelValue(l.GetValue()).IsValid() { - return fmt.Errorf("invalid label value %q", l.GetValue()) - } - if !model.LabelName(l.GetName()).IsValid() { - return fmt.Errorf("invalid label name %q", l.GetName()) - } - } - } - return nil -} - -// textDecoder implements the Decoder interface for the text protocol. -type textDecoder struct { - r io.Reader - p TextParser - fams []*dto.MetricFamily -} - -// Decode implements the Decoder interface. -func (d *textDecoder) Decode(v *dto.MetricFamily) error { - // TODO(fabxc): Wrap this as a line reader to make streaming safer. - if len(d.fams) == 0 { - // No cached metric families, read everything and parse metrics. - fams, err := d.p.TextToMetricFamilies(d.r) - if err != nil { - return err - } - if len(fams) == 0 { - return io.EOF - } - d.fams = make([]*dto.MetricFamily, 0, len(fams)) - for _, f := range fams { - d.fams = append(d.fams, f) - } - } - - *v = *d.fams[0] - d.fams = d.fams[1:] - - return nil -} - -// SampleDecoder wraps a Decoder to extract samples from the metric families -// decoded by the wrapped Decoder. -type SampleDecoder struct { - Dec Decoder - Opts *DecodeOptions - - f dto.MetricFamily -} - -// Decode calls the Decode method of the wrapped Decoder and then extracts the -// samples from the decoded MetricFamily into the provided model.Vector. -func (sd *SampleDecoder) Decode(s *model.Vector) error { - err := sd.Dec.Decode(&sd.f) - if err != nil { - return err - } - *s, err = extractSamples(&sd.f, sd.Opts) - return err -} - -// ExtractSamples builds a slice of samples from the provided metric -// families. If an error occurs during sample extraction, it continues to -// extract from the remaining metric families. The returned error is the last -// error that has occured. -func ExtractSamples(o *DecodeOptions, fams ...*dto.MetricFamily) (model.Vector, error) { - var ( - all model.Vector - lastErr error - ) - for _, f := range fams { - some, err := extractSamples(f, o) - if err != nil { - lastErr = err - continue - } - all = append(all, some...) - } - return all, lastErr -} - -func extractSamples(f *dto.MetricFamily, o *DecodeOptions) (model.Vector, error) { - switch f.GetType() { - case dto.MetricType_COUNTER: - return extractCounter(o, f), nil - case dto.MetricType_GAUGE: - return extractGauge(o, f), nil - case dto.MetricType_SUMMARY: - return extractSummary(o, f), nil - case dto.MetricType_UNTYPED: - return extractUntyped(o, f), nil - case dto.MetricType_HISTOGRAM: - return extractHistogram(o, f), nil - } - return nil, fmt.Errorf("expfmt.extractSamples: unknown metric family type %v", f.GetType()) -} - -func extractCounter(o *DecodeOptions, f *dto.MetricFamily) model.Vector { - samples := make(model.Vector, 0, len(f.Metric)) - - for _, m := range f.Metric { - if m.Counter == nil { - continue - } - - lset := make(model.LabelSet, len(m.Label)+1) - for _, p := range m.Label { - lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue()) - } - lset[model.MetricNameLabel] = model.LabelValue(f.GetName()) - - smpl := &model.Sample{ - Metric: model.Metric(lset), - Value: model.SampleValue(m.Counter.GetValue()), - } - - if m.TimestampMs != nil { - smpl.Timestamp = model.TimeFromUnixNano(*m.TimestampMs * 1000000) - } else { - smpl.Timestamp = o.Timestamp - } - - samples = append(samples, smpl) - } - - return samples -} - -func extractGauge(o *DecodeOptions, f *dto.MetricFamily) model.Vector { - samples := make(model.Vector, 0, len(f.Metric)) - - for _, m := range f.Metric { - if m.Gauge == nil { - continue - } - - lset := make(model.LabelSet, len(m.Label)+1) - for _, p := range m.Label { - lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue()) - } - lset[model.MetricNameLabel] = model.LabelValue(f.GetName()) - - smpl := &model.Sample{ - Metric: model.Metric(lset), - Value: model.SampleValue(m.Gauge.GetValue()), - } - - if m.TimestampMs != nil { - smpl.Timestamp = model.TimeFromUnixNano(*m.TimestampMs * 1000000) - } else { - smpl.Timestamp = o.Timestamp - } - - samples = append(samples, smpl) - } - - return samples -} - -func extractUntyped(o *DecodeOptions, f *dto.MetricFamily) model.Vector { - samples := make(model.Vector, 0, len(f.Metric)) - - for _, m := range f.Metric { - if m.Untyped == nil { - continue - } - - lset := make(model.LabelSet, len(m.Label)+1) - for _, p := range m.Label { - lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue()) - } - lset[model.MetricNameLabel] = model.LabelValue(f.GetName()) - - smpl := &model.Sample{ - Metric: model.Metric(lset), - Value: model.SampleValue(m.Untyped.GetValue()), - } - - if m.TimestampMs != nil { - smpl.Timestamp = model.TimeFromUnixNano(*m.TimestampMs * 1000000) - } else { - smpl.Timestamp = o.Timestamp - } - - samples = append(samples, smpl) - } - - return samples -} - -func extractSummary(o *DecodeOptions, f *dto.MetricFamily) model.Vector { - samples := make(model.Vector, 0, len(f.Metric)) - - for _, m := range f.Metric { - if m.Summary == nil { - continue - } - - timestamp := o.Timestamp - if m.TimestampMs != nil { - timestamp = model.TimeFromUnixNano(*m.TimestampMs * 1000000) - } - - for _, q := range m.Summary.Quantile { - lset := make(model.LabelSet, len(m.Label)+2) - for _, p := range m.Label { - lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue()) - } - // BUG(matt): Update other names to "quantile". - lset[model.LabelName(model.QuantileLabel)] = model.LabelValue(fmt.Sprint(q.GetQuantile())) - lset[model.MetricNameLabel] = model.LabelValue(f.GetName()) - - samples = append(samples, &model.Sample{ - Metric: model.Metric(lset), - Value: model.SampleValue(q.GetValue()), - Timestamp: timestamp, - }) - } - - lset := make(model.LabelSet, len(m.Label)+1) - for _, p := range m.Label { - lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue()) - } - lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_sum") - - samples = append(samples, &model.Sample{ - Metric: model.Metric(lset), - Value: model.SampleValue(m.Summary.GetSampleSum()), - Timestamp: timestamp, - }) - - lset = make(model.LabelSet, len(m.Label)+1) - for _, p := range m.Label { - lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue()) - } - lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_count") - - samples = append(samples, &model.Sample{ - Metric: model.Metric(lset), - Value: model.SampleValue(m.Summary.GetSampleCount()), - Timestamp: timestamp, - }) - } - - return samples -} - -func extractHistogram(o *DecodeOptions, f *dto.MetricFamily) model.Vector { - samples := make(model.Vector, 0, len(f.Metric)) - - for _, m := range f.Metric { - if m.Histogram == nil { - continue - } - - timestamp := o.Timestamp - if m.TimestampMs != nil { - timestamp = model.TimeFromUnixNano(*m.TimestampMs * 1000000) - } - - infSeen := false - - for _, q := range m.Histogram.Bucket { - lset := make(model.LabelSet, len(m.Label)+2) - for _, p := range m.Label { - lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue()) - } - lset[model.LabelName(model.BucketLabel)] = model.LabelValue(fmt.Sprint(q.GetUpperBound())) - lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_bucket") - - if math.IsInf(q.GetUpperBound(), +1) { - infSeen = true - } - - samples = append(samples, &model.Sample{ - Metric: model.Metric(lset), - Value: model.SampleValue(q.GetCumulativeCount()), - Timestamp: timestamp, - }) - } - - lset := make(model.LabelSet, len(m.Label)+1) - for _, p := range m.Label { - lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue()) - } - lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_sum") - - samples = append(samples, &model.Sample{ - Metric: model.Metric(lset), - Value: model.SampleValue(m.Histogram.GetSampleSum()), - Timestamp: timestamp, - }) - - lset = make(model.LabelSet, len(m.Label)+1) - for _, p := range m.Label { - lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue()) - } - lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_count") - - count := &model.Sample{ - Metric: model.Metric(lset), - Value: model.SampleValue(m.Histogram.GetSampleCount()), - Timestamp: timestamp, - } - samples = append(samples, count) - - if !infSeen { - // Append an infinity bucket sample. - lset := make(model.LabelSet, len(m.Label)+2) - for _, p := range m.Label { - lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue()) - } - lset[model.LabelName(model.BucketLabel)] = model.LabelValue("+Inf") - lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_bucket") - - samples = append(samples, &model.Sample{ - Metric: model.Metric(lset), - Value: count.Value, - Timestamp: timestamp, - }) - } - } - - return samples -} diff --git a/vendor/github.com/prometheus/common/expfmt/encode.go b/vendor/github.com/prometheus/common/expfmt/encode.go deleted file mode 100644 index 11839ed..0000000 --- a/vendor/github.com/prometheus/common/expfmt/encode.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2015 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. - -package expfmt - -import ( - "fmt" - "io" - "net/http" - - "github.com/golang/protobuf/proto" - "github.com/matttproud/golang_protobuf_extensions/pbutil" - "github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg" - - dto "github.com/prometheus/client_model/go" -) - -// Encoder types encode metric families into an underlying wire protocol. -type Encoder interface { - Encode(*dto.MetricFamily) error -} - -type encoder func(*dto.MetricFamily) error - -func (e encoder) Encode(v *dto.MetricFamily) error { - return e(v) -} - -// Negotiate returns the Content-Type based on the given Accept header. -// If no appropriate accepted type is found, FmtText is returned. -func Negotiate(h http.Header) Format { - for _, ac := range goautoneg.ParseAccept(h.Get(hdrAccept)) { - // Check for protocol buffer - if ac.Type+"/"+ac.SubType == ProtoType && ac.Params["proto"] == ProtoProtocol { - switch ac.Params["encoding"] { - case "delimited": - return FmtProtoDelim - case "text": - return FmtProtoText - case "compact-text": - return FmtProtoCompact - } - } - // Check for text format. - ver := ac.Params["version"] - if ac.Type == "text" && ac.SubType == "plain" && (ver == TextVersion || ver == "") { - return FmtText - } - } - return FmtText -} - -// NewEncoder returns a new encoder based on content type negotiation. -func NewEncoder(w io.Writer, format Format) Encoder { - switch format { - case FmtProtoDelim: - return encoder(func(v *dto.MetricFamily) error { - _, err := pbutil.WriteDelimited(w, v) - return err - }) - case FmtProtoCompact: - return encoder(func(v *dto.MetricFamily) error { - _, err := fmt.Fprintln(w, v.String()) - return err - }) - case FmtProtoText: - return encoder(func(v *dto.MetricFamily) error { - _, err := fmt.Fprintln(w, proto.MarshalTextString(v)) - return err - }) - case FmtText: - return encoder(func(v *dto.MetricFamily) error { - _, err := MetricFamilyToText(w, v) - return err - }) - } - panic("expfmt.NewEncoder: unknown format") -} diff --git a/vendor/github.com/prometheus/common/expfmt/expfmt.go b/vendor/github.com/prometheus/common/expfmt/expfmt.go deleted file mode 100644 index 371ac75..0000000 --- a/vendor/github.com/prometheus/common/expfmt/expfmt.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2015 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. - -// Package expfmt contains tools for reading and writing Prometheus metrics. -package expfmt - -// Format specifies the HTTP content type of the different wire protocols. -type Format string - -// Constants to assemble the Content-Type values for the different wire protocols. -const ( - TextVersion = "0.0.4" - ProtoType = `application/vnd.google.protobuf` - ProtoProtocol = `io.prometheus.client.MetricFamily` - ProtoFmt = ProtoType + "; proto=" + ProtoProtocol + ";" - - // The Content-Type values for the different wire protocols. - FmtUnknown Format = `` - FmtText Format = `text/plain; version=` + TextVersion - FmtProtoDelim Format = ProtoFmt + ` encoding=delimited` - FmtProtoText Format = ProtoFmt + ` encoding=text` - FmtProtoCompact Format = ProtoFmt + ` encoding=compact-text` -) - -const ( - hdrContentType = "Content-Type" - hdrAccept = "Accept" -) diff --git a/vendor/github.com/prometheus/common/expfmt/fuzz.go b/vendor/github.com/prometheus/common/expfmt/fuzz.go deleted file mode 100644 index dc2eede..0000000 --- a/vendor/github.com/prometheus/common/expfmt/fuzz.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2014 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 only when actually fuzzing -// +build gofuzz - -package expfmt - -import "bytes" - -// Fuzz text metric parser with with github.com/dvyukov/go-fuzz: -// -// go-fuzz-build github.com/prometheus/common/expfmt -// go-fuzz -bin expfmt-fuzz.zip -workdir fuzz -// -// Further input samples should go in the folder fuzz/corpus. -func Fuzz(in []byte) int { - parser := TextParser{} - _, err := parser.TextToMetricFamilies(bytes.NewReader(in)) - - if err != nil { - return 0 - } - - return 1 -} diff --git a/vendor/github.com/prometheus/common/expfmt/text_create.go b/vendor/github.com/prometheus/common/expfmt/text_create.go deleted file mode 100644 index f11321c..0000000 --- a/vendor/github.com/prometheus/common/expfmt/text_create.go +++ /dev/null @@ -1,303 +0,0 @@ -// Copyright 2014 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. - -package expfmt - -import ( - "fmt" - "io" - "math" - "strings" - - dto "github.com/prometheus/client_model/go" - "github.com/prometheus/common/model" -) - -// MetricFamilyToText converts a MetricFamily proto message into text format and -// writes the resulting lines to 'out'. It returns the number of bytes written -// and any error encountered. The output will have the same order as the input, -// no further sorting is performed. Furthermore, this function assumes the input -// is already sanitized and does not perform any sanity checks. If the input -// contains duplicate metrics or invalid metric or label names, the conversion -// will result in invalid text format output. -// -// This method fulfills the type 'prometheus.encoder'. -func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) { - var written int - - // Fail-fast checks. - if len(in.Metric) == 0 { - return written, fmt.Errorf("MetricFamily has no metrics: %s", in) - } - name := in.GetName() - if name == "" { - return written, fmt.Errorf("MetricFamily has no name: %s", in) - } - - // Comments, first HELP, then TYPE. - if in.Help != nil { - n, err := fmt.Fprintf( - out, "# HELP %s %s\n", - name, escapeString(*in.Help, false), - ) - written += n - if err != nil { - return written, err - } - } - metricType := in.GetType() - n, err := fmt.Fprintf( - out, "# TYPE %s %s\n", - name, strings.ToLower(metricType.String()), - ) - written += n - if err != nil { - return written, err - } - - // Finally the samples, one line for each. - for _, metric := range in.Metric { - switch metricType { - case dto.MetricType_COUNTER: - if metric.Counter == nil { - return written, fmt.Errorf( - "expected counter in metric %s %s", name, metric, - ) - } - n, err = writeSample( - name, metric, "", "", - metric.Counter.GetValue(), - out, - ) - case dto.MetricType_GAUGE: - if metric.Gauge == nil { - return written, fmt.Errorf( - "expected gauge in metric %s %s", name, metric, - ) - } - n, err = writeSample( - name, metric, "", "", - metric.Gauge.GetValue(), - out, - ) - case dto.MetricType_UNTYPED: - if metric.Untyped == nil { - return written, fmt.Errorf( - "expected untyped in metric %s %s", name, metric, - ) - } - n, err = writeSample( - name, metric, "", "", - metric.Untyped.GetValue(), - out, - ) - case dto.MetricType_SUMMARY: - if metric.Summary == nil { - return written, fmt.Errorf( - "expected summary in metric %s %s", name, metric, - ) - } - for _, q := range metric.Summary.Quantile { - n, err = writeSample( - name, metric, - model.QuantileLabel, fmt.Sprint(q.GetQuantile()), - q.GetValue(), - out, - ) - written += n - if err != nil { - return written, err - } - } - n, err = writeSample( - name+"_sum", metric, "", "", - metric.Summary.GetSampleSum(), - out, - ) - if err != nil { - return written, err - } - written += n - n, err = writeSample( - name+"_count", metric, "", "", - float64(metric.Summary.GetSampleCount()), - out, - ) - case dto.MetricType_HISTOGRAM: - if metric.Histogram == nil { - return written, fmt.Errorf( - "expected histogram in metric %s %s", name, metric, - ) - } - infSeen := false - for _, q := range metric.Histogram.Bucket { - n, err = writeSample( - name+"_bucket", metric, - model.BucketLabel, fmt.Sprint(q.GetUpperBound()), - float64(q.GetCumulativeCount()), - out, - ) - written += n - if err != nil { - return written, err - } - if math.IsInf(q.GetUpperBound(), +1) { - infSeen = true - } - } - if !infSeen { - n, err = writeSample( - name+"_bucket", metric, - model.BucketLabel, "+Inf", - float64(metric.Histogram.GetSampleCount()), - out, - ) - if err != nil { - return written, err - } - written += n - } - n, err = writeSample( - name+"_sum", metric, "", "", - metric.Histogram.GetSampleSum(), - out, - ) - if err != nil { - return written, err - } - written += n - n, err = writeSample( - name+"_count", metric, "", "", - float64(metric.Histogram.GetSampleCount()), - out, - ) - default: - return written, fmt.Errorf( - "unexpected type in metric %s %s", name, metric, - ) - } - written += n - if err != nil { - return written, err - } - } - return written, nil -} - -// writeSample writes a single sample in text format to out, given the metric -// name, the metric proto message itself, optionally an additional label name -// and value (use empty strings if not required), and the value. The function -// returns the number of bytes written and any error encountered. -func writeSample( - name string, - metric *dto.Metric, - additionalLabelName, additionalLabelValue string, - value float64, - out io.Writer, -) (int, error) { - var written int - n, err := fmt.Fprint(out, name) - written += n - if err != nil { - return written, err - } - n, err = labelPairsToText( - metric.Label, - additionalLabelName, additionalLabelValue, - out, - ) - written += n - if err != nil { - return written, err - } - n, err = fmt.Fprintf(out, " %v", value) - written += n - if err != nil { - return written, err - } - if metric.TimestampMs != nil { - n, err = fmt.Fprintf(out, " %v", *metric.TimestampMs) - written += n - if err != nil { - return written, err - } - } - n, err = out.Write([]byte{'\n'}) - written += n - if err != nil { - return written, err - } - return written, nil -} - -// labelPairsToText converts a slice of LabelPair proto messages plus the -// explicitly given additional label pair into text formatted as required by the -// text format and writes it to 'out'. An empty slice in combination with an -// empty string 'additionalLabelName' results in nothing being -// written. Otherwise, the label pairs are written, escaped as required by the -// text format, and enclosed in '{...}'. The function returns the number of -// bytes written and any error encountered. -func labelPairsToText( - in []*dto.LabelPair, - additionalLabelName, additionalLabelValue string, - out io.Writer, -) (int, error) { - if len(in) == 0 && additionalLabelName == "" { - return 0, nil - } - var written int - separator := '{' - for _, lp := range in { - n, err := fmt.Fprintf( - out, `%c%s="%s"`, - separator, lp.GetName(), escapeString(lp.GetValue(), true), - ) - written += n - if err != nil { - return written, err - } - separator = ',' - } - if additionalLabelName != "" { - n, err := fmt.Fprintf( - out, `%c%s="%s"`, - separator, additionalLabelName, - escapeString(additionalLabelValue, true), - ) - written += n - if err != nil { - return written, err - } - } - n, err := out.Write([]byte{'}'}) - written += n - if err != nil { - return written, err - } - return written, nil -} - -var ( - escape = strings.NewReplacer("\\", `\\`, "\n", `\n`) - escapeWithDoubleQuote = strings.NewReplacer("\\", `\\`, "\n", `\n`, "\"", `\"`) -) - -// escapeString replaces '\' by '\\', new line character by '\n', and - if -// includeDoubleQuote is true - '"' by '\"'. -func escapeString(v string, includeDoubleQuote bool) string { - if includeDoubleQuote { - return escapeWithDoubleQuote.Replace(v) - } - - return escape.Replace(v) -} diff --git a/vendor/github.com/prometheus/common/expfmt/text_parse.go b/vendor/github.com/prometheus/common/expfmt/text_parse.go deleted file mode 100644 index 54bcfde..0000000 --- a/vendor/github.com/prometheus/common/expfmt/text_parse.go +++ /dev/null @@ -1,757 +0,0 @@ -// Copyright 2014 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. - -package expfmt - -import ( - "bufio" - "bytes" - "fmt" - "io" - "math" - "strconv" - "strings" - - dto "github.com/prometheus/client_model/go" - - "github.com/golang/protobuf/proto" - "github.com/prometheus/common/model" -) - -// A stateFn is a function that represents a state in a state machine. By -// executing it, the state is progressed to the next state. The stateFn returns -// another stateFn, which represents the new state. The end state is represented -// by nil. -type stateFn func() stateFn - -// ParseError signals errors while parsing the simple and flat text-based -// exchange format. -type ParseError struct { - Line int - Msg string -} - -// Error implements the error interface. -func (e ParseError) Error() string { - return fmt.Sprintf("text format parsing error in line %d: %s", e.Line, e.Msg) -} - -// TextParser is used to parse the simple and flat text-based exchange format. Its -// zero value is ready to use. -type TextParser struct { - metricFamiliesByName map[string]*dto.MetricFamily - buf *bufio.Reader // Where the parsed input is read through. - err error // Most recent error. - lineCount int // Tracks the line count for error messages. - currentByte byte // The most recent byte read. - currentToken bytes.Buffer // Re-used each time a token has to be gathered from multiple bytes. - currentMF *dto.MetricFamily - currentMetric *dto.Metric - currentLabelPair *dto.LabelPair - - // The remaining member variables are only used for summaries/histograms. - currentLabels map[string]string // All labels including '__name__' but excluding 'quantile'/'le' - // Summary specific. - summaries map[uint64]*dto.Metric // Key is created with LabelsToSignature. - currentQuantile float64 - // Histogram specific. - histograms map[uint64]*dto.Metric // Key is created with LabelsToSignature. - currentBucket float64 - // These tell us if the currently processed line ends on '_count' or - // '_sum' respectively and belong to a summary/histogram, representing the sample - // count and sum of that summary/histogram. - currentIsSummaryCount, currentIsSummarySum bool - currentIsHistogramCount, currentIsHistogramSum bool -} - -// TextToMetricFamilies reads 'in' as the simple and flat text-based exchange -// format and creates MetricFamily proto messages. It returns the MetricFamily -// proto messages in a map where the metric names are the keys, along with any -// error encountered. -// -// If the input contains duplicate metrics (i.e. lines with the same metric name -// and exactly the same label set), the resulting MetricFamily will contain -// duplicate Metric proto messages. Similar is true for duplicate label -// names. Checks for duplicates have to be performed separately, if required. -// Also note that neither the metrics within each MetricFamily are sorted nor -// the label pairs within each Metric. Sorting is not required for the most -// frequent use of this method, which is sample ingestion in the Prometheus -// server. However, for presentation purposes, you might want to sort the -// metrics, and in some cases, you must sort the labels, e.g. for consumption by -// the metric family injection hook of the Prometheus registry. -// -// Summaries and histograms are rather special beasts. You would probably not -// use them in the simple text format anyway. This method can deal with -// summaries and histograms if they are presented in exactly the way the -// text.Create function creates them. -// -// This method must not be called concurrently. If you want to parse different -// input concurrently, instantiate a separate Parser for each goroutine. -func (p *TextParser) TextToMetricFamilies(in io.Reader) (map[string]*dto.MetricFamily, error) { - p.reset(in) - for nextState := p.startOfLine; nextState != nil; nextState = nextState() { - // Magic happens here... - } - // Get rid of empty metric families. - for k, mf := range p.metricFamiliesByName { - if len(mf.GetMetric()) == 0 { - delete(p.metricFamiliesByName, k) - } - } - // If p.err is io.EOF now, we have run into a premature end of the input - // stream. Turn this error into something nicer and more - // meaningful. (io.EOF is often used as a signal for the legitimate end - // of an input stream.) - if p.err == io.EOF { - p.parseError("unexpected end of input stream") - } - return p.metricFamiliesByName, p.err -} - -func (p *TextParser) reset(in io.Reader) { - p.metricFamiliesByName = map[string]*dto.MetricFamily{} - if p.buf == nil { - p.buf = bufio.NewReader(in) - } else { - p.buf.Reset(in) - } - p.err = nil - p.lineCount = 0 - if p.summaries == nil || len(p.summaries) > 0 { - p.summaries = map[uint64]*dto.Metric{} - } - if p.histograms == nil || len(p.histograms) > 0 { - p.histograms = map[uint64]*dto.Metric{} - } - p.currentQuantile = math.NaN() - p.currentBucket = math.NaN() -} - -// startOfLine represents the state where the next byte read from p.buf is the -// start of a line (or whitespace leading up to it). -func (p *TextParser) startOfLine() stateFn { - p.lineCount++ - if p.skipBlankTab(); p.err != nil { - // End of input reached. This is the only case where - // that is not an error but a signal that we are done. - p.err = nil - return nil - } - switch p.currentByte { - case '#': - return p.startComment - case '\n': - return p.startOfLine // Empty line, start the next one. - } - return p.readingMetricName -} - -// startComment represents the state where the next byte read from p.buf is the -// start of a comment (or whitespace leading up to it). -func (p *TextParser) startComment() stateFn { - if p.skipBlankTab(); p.err != nil { - return nil // Unexpected end of input. - } - if p.currentByte == '\n' { - return p.startOfLine - } - if p.readTokenUntilWhitespace(); p.err != nil { - return nil // Unexpected end of input. - } - // If we have hit the end of line already, there is nothing left - // to do. This is not considered a syntax error. - if p.currentByte == '\n' { - return p.startOfLine - } - keyword := p.currentToken.String() - if keyword != "HELP" && keyword != "TYPE" { - // Generic comment, ignore by fast forwarding to end of line. - for p.currentByte != '\n' { - if p.currentByte, p.err = p.buf.ReadByte(); p.err != nil { - return nil // Unexpected end of input. - } - } - return p.startOfLine - } - // There is something. Next has to be a metric name. - if p.skipBlankTab(); p.err != nil { - return nil // Unexpected end of input. - } - if p.readTokenAsMetricName(); p.err != nil { - return nil // Unexpected end of input. - } - if p.currentByte == '\n' { - // At the end of the line already. - // Again, this is not considered a syntax error. - return p.startOfLine - } - if !isBlankOrTab(p.currentByte) { - p.parseError("invalid metric name in comment") - return nil - } - p.setOrCreateCurrentMF() - if p.skipBlankTab(); p.err != nil { - return nil // Unexpected end of input. - } - if p.currentByte == '\n' { - // At the end of the line already. - // Again, this is not considered a syntax error. - return p.startOfLine - } - switch keyword { - case "HELP": - return p.readingHelp - case "TYPE": - return p.readingType - } - panic(fmt.Sprintf("code error: unexpected keyword %q", keyword)) -} - -// readingMetricName represents the state where the last byte read (now in -// p.currentByte) is the first byte of a metric name. -func (p *TextParser) readingMetricName() stateFn { - if p.readTokenAsMetricName(); p.err != nil { - return nil - } - if p.currentToken.Len() == 0 { - p.parseError("invalid metric name") - return nil - } - p.setOrCreateCurrentMF() - // Now is the time to fix the type if it hasn't happened yet. - if p.currentMF.Type == nil { - p.currentMF.Type = dto.MetricType_UNTYPED.Enum() - } - p.currentMetric = &dto.Metric{} - // Do not append the newly created currentMetric to - // currentMF.Metric right now. First wait if this is a summary, - // and the metric exists already, which we can only know after - // having read all the labels. - if p.skipBlankTabIfCurrentBlankTab(); p.err != nil { - return nil // Unexpected end of input. - } - return p.readingLabels -} - -// readingLabels represents the state where the last byte read (now in -// p.currentByte) is either the first byte of the label set (i.e. a '{'), or the -// first byte of the value (otherwise). -func (p *TextParser) readingLabels() stateFn { - // Summaries/histograms are special. We have to reset the - // currentLabels map, currentQuantile and currentBucket before starting to - // read labels. - if p.currentMF.GetType() == dto.MetricType_SUMMARY || p.currentMF.GetType() == dto.MetricType_HISTOGRAM { - p.currentLabels = map[string]string{} - p.currentLabels[string(model.MetricNameLabel)] = p.currentMF.GetName() - p.currentQuantile = math.NaN() - p.currentBucket = math.NaN() - } - if p.currentByte != '{' { - return p.readingValue - } - return p.startLabelName -} - -// startLabelName represents the state where the next byte read from p.buf is -// the start of a label name (or whitespace leading up to it). -func (p *TextParser) startLabelName() stateFn { - if p.skipBlankTab(); p.err != nil { - return nil // Unexpected end of input. - } - if p.currentByte == '}' { - if p.skipBlankTab(); p.err != nil { - return nil // Unexpected end of input. - } - return p.readingValue - } - if p.readTokenAsLabelName(); p.err != nil { - return nil // Unexpected end of input. - } - if p.currentToken.Len() == 0 { - p.parseError(fmt.Sprintf("invalid label name for metric %q", p.currentMF.GetName())) - return nil - } - p.currentLabelPair = &dto.LabelPair{Name: proto.String(p.currentToken.String())} - if p.currentLabelPair.GetName() == string(model.MetricNameLabel) { - p.parseError(fmt.Sprintf("label name %q is reserved", model.MetricNameLabel)) - return nil - } - // Special summary/histogram treatment. Don't add 'quantile' and 'le' - // labels to 'real' labels. - if !(p.currentMF.GetType() == dto.MetricType_SUMMARY && p.currentLabelPair.GetName() == model.QuantileLabel) && - !(p.currentMF.GetType() == dto.MetricType_HISTOGRAM && p.currentLabelPair.GetName() == model.BucketLabel) { - p.currentMetric.Label = append(p.currentMetric.Label, p.currentLabelPair) - } - if p.skipBlankTabIfCurrentBlankTab(); p.err != nil { - return nil // Unexpected end of input. - } - if p.currentByte != '=' { - p.parseError(fmt.Sprintf("expected '=' after label name, found %q", p.currentByte)) - return nil - } - return p.startLabelValue -} - -// startLabelValue represents the state where the next byte read from p.buf is -// the start of a (quoted) label value (or whitespace leading up to it). -func (p *TextParser) startLabelValue() stateFn { - if p.skipBlankTab(); p.err != nil { - return nil // Unexpected end of input. - } - if p.currentByte != '"' { - p.parseError(fmt.Sprintf("expected '\"' at start of label value, found %q", p.currentByte)) - return nil - } - if p.readTokenAsLabelValue(); p.err != nil { - return nil - } - if !model.LabelValue(p.currentToken.String()).IsValid() { - p.parseError(fmt.Sprintf("invalid label value %q", p.currentToken.String())) - return nil - } - p.currentLabelPair.Value = proto.String(p.currentToken.String()) - // Special treatment of summaries: - // - Quantile labels are special, will result in dto.Quantile later. - // - Other labels have to be added to currentLabels for signature calculation. - if p.currentMF.GetType() == dto.MetricType_SUMMARY { - if p.currentLabelPair.GetName() == model.QuantileLabel { - if p.currentQuantile, p.err = strconv.ParseFloat(p.currentLabelPair.GetValue(), 64); p.err != nil { - // Create a more helpful error message. - p.parseError(fmt.Sprintf("expected float as value for 'quantile' label, got %q", p.currentLabelPair.GetValue())) - return nil - } - } else { - p.currentLabels[p.currentLabelPair.GetName()] = p.currentLabelPair.GetValue() - } - } - // Similar special treatment of histograms. - if p.currentMF.GetType() == dto.MetricType_HISTOGRAM { - if p.currentLabelPair.GetName() == model.BucketLabel { - if p.currentBucket, p.err = strconv.ParseFloat(p.currentLabelPair.GetValue(), 64); p.err != nil { - // Create a more helpful error message. - p.parseError(fmt.Sprintf("expected float as value for 'le' label, got %q", p.currentLabelPair.GetValue())) - return nil - } - } else { - p.currentLabels[p.currentLabelPair.GetName()] = p.currentLabelPair.GetValue() - } - } - if p.skipBlankTab(); p.err != nil { - return nil // Unexpected end of input. - } - switch p.currentByte { - case ',': - return p.startLabelName - - case '}': - if p.skipBlankTab(); p.err != nil { - return nil // Unexpected end of input. - } - return p.readingValue - default: - p.parseError(fmt.Sprintf("unexpected end of label value %q", p.currentLabelPair.Value)) - return nil - } -} - -// readingValue represents the state where the last byte read (now in -// p.currentByte) is the first byte of the sample value (i.e. a float). -func (p *TextParser) readingValue() stateFn { - // When we are here, we have read all the labels, so for the - // special case of a summary/histogram, we can finally find out - // if the metric already exists. - if p.currentMF.GetType() == dto.MetricType_SUMMARY { - signature := model.LabelsToSignature(p.currentLabels) - if summary := p.summaries[signature]; summary != nil { - p.currentMetric = summary - } else { - p.summaries[signature] = p.currentMetric - p.currentMF.Metric = append(p.currentMF.Metric, p.currentMetric) - } - } else if p.currentMF.GetType() == dto.MetricType_HISTOGRAM { - signature := model.LabelsToSignature(p.currentLabels) - if histogram := p.histograms[signature]; histogram != nil { - p.currentMetric = histogram - } else { - p.histograms[signature] = p.currentMetric - p.currentMF.Metric = append(p.currentMF.Metric, p.currentMetric) - } - } else { - p.currentMF.Metric = append(p.currentMF.Metric, p.currentMetric) - } - if p.readTokenUntilWhitespace(); p.err != nil { - return nil // Unexpected end of input. - } - value, err := strconv.ParseFloat(p.currentToken.String(), 64) - if err != nil { - // Create a more helpful error message. - p.parseError(fmt.Sprintf("expected float as value, got %q", p.currentToken.String())) - return nil - } - switch p.currentMF.GetType() { - case dto.MetricType_COUNTER: - p.currentMetric.Counter = &dto.Counter{Value: proto.Float64(value)} - case dto.MetricType_GAUGE: - p.currentMetric.Gauge = &dto.Gauge{Value: proto.Float64(value)} - case dto.MetricType_UNTYPED: - p.currentMetric.Untyped = &dto.Untyped{Value: proto.Float64(value)} - case dto.MetricType_SUMMARY: - // *sigh* - if p.currentMetric.Summary == nil { - p.currentMetric.Summary = &dto.Summary{} - } - switch { - case p.currentIsSummaryCount: - p.currentMetric.Summary.SampleCount = proto.Uint64(uint64(value)) - case p.currentIsSummarySum: - p.currentMetric.Summary.SampleSum = proto.Float64(value) - case !math.IsNaN(p.currentQuantile): - p.currentMetric.Summary.Quantile = append( - p.currentMetric.Summary.Quantile, - &dto.Quantile{ - Quantile: proto.Float64(p.currentQuantile), - Value: proto.Float64(value), - }, - ) - } - case dto.MetricType_HISTOGRAM: - // *sigh* - if p.currentMetric.Histogram == nil { - p.currentMetric.Histogram = &dto.Histogram{} - } - switch { - case p.currentIsHistogramCount: - p.currentMetric.Histogram.SampleCount = proto.Uint64(uint64(value)) - case p.currentIsHistogramSum: - p.currentMetric.Histogram.SampleSum = proto.Float64(value) - case !math.IsNaN(p.currentBucket): - p.currentMetric.Histogram.Bucket = append( - p.currentMetric.Histogram.Bucket, - &dto.Bucket{ - UpperBound: proto.Float64(p.currentBucket), - CumulativeCount: proto.Uint64(uint64(value)), - }, - ) - } - default: - p.err = fmt.Errorf("unexpected type for metric name %q", p.currentMF.GetName()) - } - if p.currentByte == '\n' { - return p.startOfLine - } - return p.startTimestamp -} - -// startTimestamp represents the state where the next byte read from p.buf is -// the start of the timestamp (or whitespace leading up to it). -func (p *TextParser) startTimestamp() stateFn { - if p.skipBlankTab(); p.err != nil { - return nil // Unexpected end of input. - } - if p.readTokenUntilWhitespace(); p.err != nil { - return nil // Unexpected end of input. - } - timestamp, err := strconv.ParseInt(p.currentToken.String(), 10, 64) - if err != nil { - // Create a more helpful error message. - p.parseError(fmt.Sprintf("expected integer as timestamp, got %q", p.currentToken.String())) - return nil - } - p.currentMetric.TimestampMs = proto.Int64(timestamp) - if p.readTokenUntilNewline(false); p.err != nil { - return nil // Unexpected end of input. - } - if p.currentToken.Len() > 0 { - p.parseError(fmt.Sprintf("spurious string after timestamp: %q", p.currentToken.String())) - return nil - } - return p.startOfLine -} - -// readingHelp represents the state where the last byte read (now in -// p.currentByte) is the first byte of the docstring after 'HELP'. -func (p *TextParser) readingHelp() stateFn { - if p.currentMF.Help != nil { - p.parseError(fmt.Sprintf("second HELP line for metric name %q", p.currentMF.GetName())) - return nil - } - // Rest of line is the docstring. - if p.readTokenUntilNewline(true); p.err != nil { - return nil // Unexpected end of input. - } - p.currentMF.Help = proto.String(p.currentToken.String()) - return p.startOfLine -} - -// readingType represents the state where the last byte read (now in -// p.currentByte) is the first byte of the type hint after 'HELP'. -func (p *TextParser) readingType() stateFn { - if p.currentMF.Type != nil { - p.parseError(fmt.Sprintf("second TYPE line for metric name %q, or TYPE reported after samples", p.currentMF.GetName())) - return nil - } - // Rest of line is the type. - if p.readTokenUntilNewline(false); p.err != nil { - return nil // Unexpected end of input. - } - metricType, ok := dto.MetricType_value[strings.ToUpper(p.currentToken.String())] - if !ok { - p.parseError(fmt.Sprintf("unknown metric type %q", p.currentToken.String())) - return nil - } - p.currentMF.Type = dto.MetricType(metricType).Enum() - return p.startOfLine -} - -// parseError sets p.err to a ParseError at the current line with the given -// message. -func (p *TextParser) parseError(msg string) { - p.err = ParseError{ - Line: p.lineCount, - Msg: msg, - } -} - -// skipBlankTab reads (and discards) bytes from p.buf until it encounters a byte -// that is neither ' ' nor '\t'. That byte is left in p.currentByte. -func (p *TextParser) skipBlankTab() { - for { - if p.currentByte, p.err = p.buf.ReadByte(); p.err != nil || !isBlankOrTab(p.currentByte) { - return - } - } -} - -// skipBlankTabIfCurrentBlankTab works exactly as skipBlankTab but doesn't do -// anything if p.currentByte is neither ' ' nor '\t'. -func (p *TextParser) skipBlankTabIfCurrentBlankTab() { - if isBlankOrTab(p.currentByte) { - p.skipBlankTab() - } -} - -// readTokenUntilWhitespace copies bytes from p.buf into p.currentToken. The -// first byte considered is the byte already read (now in p.currentByte). The -// first whitespace byte encountered is still copied into p.currentByte, but not -// into p.currentToken. -func (p *TextParser) readTokenUntilWhitespace() { - p.currentToken.Reset() - for p.err == nil && !isBlankOrTab(p.currentByte) && p.currentByte != '\n' { - p.currentToken.WriteByte(p.currentByte) - p.currentByte, p.err = p.buf.ReadByte() - } -} - -// readTokenUntilNewline copies bytes from p.buf into p.currentToken. The first -// byte considered is the byte already read (now in p.currentByte). The first -// newline byte encountered is still copied into p.currentByte, but not into -// p.currentToken. If recognizeEscapeSequence is true, two escape sequences are -// recognized: '\\' tranlates into '\', and '\n' into a line-feed character. All -// other escape sequences are invalid and cause an error. -func (p *TextParser) readTokenUntilNewline(recognizeEscapeSequence bool) { - p.currentToken.Reset() - escaped := false - for p.err == nil { - if recognizeEscapeSequence && escaped { - switch p.currentByte { - case '\\': - p.currentToken.WriteByte(p.currentByte) - case 'n': - p.currentToken.WriteByte('\n') - default: - p.parseError(fmt.Sprintf("invalid escape sequence '\\%c'", p.currentByte)) - return - } - escaped = false - } else { - switch p.currentByte { - case '\n': - return - case '\\': - escaped = true - default: - p.currentToken.WriteByte(p.currentByte) - } - } - p.currentByte, p.err = p.buf.ReadByte() - } -} - -// readTokenAsMetricName copies a metric name from p.buf into p.currentToken. -// The first byte considered is the byte already read (now in p.currentByte). -// The first byte not part of a metric name is still copied into p.currentByte, -// but not into p.currentToken. -func (p *TextParser) readTokenAsMetricName() { - p.currentToken.Reset() - if !isValidMetricNameStart(p.currentByte) { - return - } - for { - p.currentToken.WriteByte(p.currentByte) - p.currentByte, p.err = p.buf.ReadByte() - if p.err != nil || !isValidMetricNameContinuation(p.currentByte) { - return - } - } -} - -// readTokenAsLabelName copies a label name from p.buf into p.currentToken. -// The first byte considered is the byte already read (now in p.currentByte). -// The first byte not part of a label name is still copied into p.currentByte, -// but not into p.currentToken. -func (p *TextParser) readTokenAsLabelName() { - p.currentToken.Reset() - if !isValidLabelNameStart(p.currentByte) { - return - } - for { - p.currentToken.WriteByte(p.currentByte) - p.currentByte, p.err = p.buf.ReadByte() - if p.err != nil || !isValidLabelNameContinuation(p.currentByte) { - return - } - } -} - -// readTokenAsLabelValue copies a label value from p.buf into p.currentToken. -// In contrast to the other 'readTokenAs...' functions, which start with the -// last read byte in p.currentByte, this method ignores p.currentByte and starts -// with reading a new byte from p.buf. The first byte not part of a label value -// is still copied into p.currentByte, but not into p.currentToken. -func (p *TextParser) readTokenAsLabelValue() { - p.currentToken.Reset() - escaped := false - for { - if p.currentByte, p.err = p.buf.ReadByte(); p.err != nil { - return - } - if escaped { - switch p.currentByte { - case '"', '\\': - p.currentToken.WriteByte(p.currentByte) - case 'n': - p.currentToken.WriteByte('\n') - default: - p.parseError(fmt.Sprintf("invalid escape sequence '\\%c'", p.currentByte)) - return - } - escaped = false - continue - } - switch p.currentByte { - case '"': - return - case '\n': - p.parseError(fmt.Sprintf("label value %q contains unescaped new-line", p.currentToken.String())) - return - case '\\': - escaped = true - default: - p.currentToken.WriteByte(p.currentByte) - } - } -} - -func (p *TextParser) setOrCreateCurrentMF() { - p.currentIsSummaryCount = false - p.currentIsSummarySum = false - p.currentIsHistogramCount = false - p.currentIsHistogramSum = false - name := p.currentToken.String() - if p.currentMF = p.metricFamiliesByName[name]; p.currentMF != nil { - return - } - // Try out if this is a _sum or _count for a summary/histogram. - summaryName := summaryMetricName(name) - if p.currentMF = p.metricFamiliesByName[summaryName]; p.currentMF != nil { - if p.currentMF.GetType() == dto.MetricType_SUMMARY { - if isCount(name) { - p.currentIsSummaryCount = true - } - if isSum(name) { - p.currentIsSummarySum = true - } - return - } - } - histogramName := histogramMetricName(name) - if p.currentMF = p.metricFamiliesByName[histogramName]; p.currentMF != nil { - if p.currentMF.GetType() == dto.MetricType_HISTOGRAM { - if isCount(name) { - p.currentIsHistogramCount = true - } - if isSum(name) { - p.currentIsHistogramSum = true - } - return - } - } - p.currentMF = &dto.MetricFamily{Name: proto.String(name)} - p.metricFamiliesByName[name] = p.currentMF -} - -func isValidLabelNameStart(b byte) bool { - return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || b == '_' -} - -func isValidLabelNameContinuation(b byte) bool { - return isValidLabelNameStart(b) || (b >= '0' && b <= '9') -} - -func isValidMetricNameStart(b byte) bool { - return isValidLabelNameStart(b) || b == ':' -} - -func isValidMetricNameContinuation(b byte) bool { - return isValidLabelNameContinuation(b) || b == ':' -} - -func isBlankOrTab(b byte) bool { - return b == ' ' || b == '\t' -} - -func isCount(name string) bool { - return len(name) > 6 && name[len(name)-6:] == "_count" -} - -func isSum(name string) bool { - return len(name) > 4 && name[len(name)-4:] == "_sum" -} - -func isBucket(name string) bool { - return len(name) > 7 && name[len(name)-7:] == "_bucket" -} - -func summaryMetricName(name string) string { - switch { - case isCount(name): - return name[:len(name)-6] - case isSum(name): - return name[:len(name)-4] - default: - return name - } -} - -func histogramMetricName(name string) string { - switch { - case isCount(name): - return name[:len(name)-6] - case isSum(name): - return name[:len(name)-4] - case isBucket(name): - return name[:len(name)-7] - default: - return name - } -} diff --git a/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/README.txt b/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/README.txt deleted file mode 100644 index 7723656..0000000 --- a/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/README.txt +++ /dev/null @@ -1,67 +0,0 @@ -PACKAGE - -package goautoneg -import "bitbucket.org/ww/goautoneg" - -HTTP Content-Type Autonegotiation. - -The functions in this package implement the behaviour specified in -http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html - -Copyright (c) 2011, Open Knowledge Foundation Ltd. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - Neither the name of the Open Knowledge Foundation Ltd. nor the - names of its contributors may be used to endorse or promote - products derived from this software without specific prior written - permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -FUNCTIONS - -func Negotiate(header string, alternatives []string) (content_type string) -Negotiate the most appropriate content_type given the accept header -and a list of alternatives. - -func ParseAccept(header string) (accept []Accept) -Parse an Accept Header string returning a sorted list -of clauses - - -TYPES - -type Accept struct { - Type, SubType string - Q float32 - Params map[string]string -} -Structure to represent a clause in an HTTP Accept Header - - -SUBDIRECTORIES - - .hg diff --git a/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go b/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go deleted file mode 100644 index 648b38c..0000000 --- a/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go +++ /dev/null @@ -1,162 +0,0 @@ -/* -HTTP Content-Type Autonegotiation. - -The functions in this package implement the behaviour specified in -http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html - -Copyright (c) 2011, Open Knowledge Foundation Ltd. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - Neither the name of the Open Knowledge Foundation Ltd. nor the - names of its contributors may be used to endorse or promote - products derived from this software without specific prior written - permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -*/ -package goautoneg - -import ( - "sort" - "strconv" - "strings" -) - -// Structure to represent a clause in an HTTP Accept Header -type Accept struct { - Type, SubType string - Q float64 - Params map[string]string -} - -// For internal use, so that we can use the sort interface -type accept_slice []Accept - -func (accept accept_slice) Len() int { - slice := []Accept(accept) - return len(slice) -} - -func (accept accept_slice) Less(i, j int) bool { - slice := []Accept(accept) - ai, aj := slice[i], slice[j] - if ai.Q > aj.Q { - return true - } - if ai.Type != "*" && aj.Type == "*" { - return true - } - if ai.SubType != "*" && aj.SubType == "*" { - return true - } - return false -} - -func (accept accept_slice) Swap(i, j int) { - slice := []Accept(accept) - slice[i], slice[j] = slice[j], slice[i] -} - -// Parse an Accept Header string returning a sorted list -// of clauses -func ParseAccept(header string) (accept []Accept) { - parts := strings.Split(header, ",") - accept = make([]Accept, 0, len(parts)) - for _, part := range parts { - part := strings.Trim(part, " ") - - a := Accept{} - a.Params = make(map[string]string) - a.Q = 1.0 - - mrp := strings.Split(part, ";") - - media_range := mrp[0] - sp := strings.Split(media_range, "/") - a.Type = strings.Trim(sp[0], " ") - - switch { - case len(sp) == 1 && a.Type == "*": - a.SubType = "*" - case len(sp) == 2: - a.SubType = strings.Trim(sp[1], " ") - default: - continue - } - - if len(mrp) == 1 { - accept = append(accept, a) - continue - } - - for _, param := range mrp[1:] { - sp := strings.SplitN(param, "=", 2) - if len(sp) != 2 { - continue - } - token := strings.Trim(sp[0], " ") - if token == "q" { - a.Q, _ = strconv.ParseFloat(sp[1], 32) - } else { - a.Params[token] = strings.Trim(sp[1], " ") - } - } - - accept = append(accept, a) - } - - slice := accept_slice(accept) - sort.Sort(slice) - - return -} - -// Negotiate the most appropriate content_type given the accept header -// and a list of alternatives. -func Negotiate(header string, alternatives []string) (content_type string) { - asp := make([][]string, 0, len(alternatives)) - for _, ctype := range alternatives { - asp = append(asp, strings.SplitN(ctype, "/", 2)) - } - for _, clause := range ParseAccept(header) { - for i, ctsp := range asp { - if clause.Type == ctsp[0] && clause.SubType == ctsp[1] { - content_type = alternatives[i] - return - } - if clause.Type == ctsp[0] && clause.SubType == "*" { - content_type = alternatives[i] - return - } - if clause.Type == "*" && clause.SubType == "*" { - content_type = alternatives[i] - return - } - } - } - return -} diff --git a/vendor/github.com/prometheus/common/model/alert.go b/vendor/github.com/prometheus/common/model/alert.go deleted file mode 100644 index 35e739c..0000000 --- a/vendor/github.com/prometheus/common/model/alert.go +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2013 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. - -package model - -import ( - "fmt" - "time" -) - -type AlertStatus string - -const ( - AlertFiring AlertStatus = "firing" - AlertResolved AlertStatus = "resolved" -) - -// Alert is a generic representation of an alert in the Prometheus eco-system. -type Alert struct { - // Label value pairs for purpose of aggregation, matching, and disposition - // dispatching. This must minimally include an "alertname" label. - Labels LabelSet `json:"labels"` - - // Extra key/value information which does not define alert identity. - Annotations LabelSet `json:"annotations"` - - // The known time range for this alert. Both ends are optional. - StartsAt time.Time `json:"startsAt,omitempty"` - EndsAt time.Time `json:"endsAt,omitempty"` - GeneratorURL string `json:"generatorURL"` -} - -// Name returns the name of the alert. It is equivalent to the "alertname" label. -func (a *Alert) Name() string { - return string(a.Labels[AlertNameLabel]) -} - -// Fingerprint returns a unique hash for the alert. It is equivalent to -// the fingerprint of the alert's label set. -func (a *Alert) Fingerprint() Fingerprint { - return a.Labels.Fingerprint() -} - -func (a *Alert) String() string { - s := fmt.Sprintf("%s[%s]", a.Name(), a.Fingerprint().String()[:7]) - if a.Resolved() { - return s + "[resolved]" - } - return s + "[active]" -} - -// Resolved returns true iff the activity interval ended in the past. -func (a *Alert) Resolved() bool { - return a.ResolvedAt(time.Now()) -} - -// ResolvedAt returns true off the activity interval ended before -// the given timestamp. -func (a *Alert) ResolvedAt(ts time.Time) bool { - if a.EndsAt.IsZero() { - return false - } - return !a.EndsAt.After(ts) -} - -// Status returns the status of the alert. -func (a *Alert) Status() AlertStatus { - if a.Resolved() { - return AlertResolved - } - return AlertFiring -} - -// Validate checks whether the alert data is inconsistent. -func (a *Alert) Validate() error { - if a.StartsAt.IsZero() { - return fmt.Errorf("start time missing") - } - if !a.EndsAt.IsZero() && a.EndsAt.Before(a.StartsAt) { - return fmt.Errorf("start time must be before end time") - } - if err := a.Labels.Validate(); err != nil { - return fmt.Errorf("invalid label set: %s", err) - } - if len(a.Labels) == 0 { - return fmt.Errorf("at least one label pair required") - } - if err := a.Annotations.Validate(); err != nil { - return fmt.Errorf("invalid annotations: %s", err) - } - return nil -} - -// Alert is a list of alerts that can be sorted in chronological order. -type Alerts []*Alert - -func (as Alerts) Len() int { return len(as) } -func (as Alerts) Swap(i, j int) { as[i], as[j] = as[j], as[i] } - -func (as Alerts) Less(i, j int) bool { - if as[i].StartsAt.Before(as[j].StartsAt) { - return true - } - if as[i].EndsAt.Before(as[j].EndsAt) { - return true - } - return as[i].Fingerprint() < as[j].Fingerprint() -} - -// HasFiring returns true iff one of the alerts is not resolved. -func (as Alerts) HasFiring() bool { - for _, a := range as { - if !a.Resolved() { - return true - } - } - return false -} - -// Status returns StatusFiring iff at least one of the alerts is firing. -func (as Alerts) Status() AlertStatus { - if as.HasFiring() { - return AlertFiring - } - return AlertResolved -} diff --git a/vendor/github.com/prometheus/common/model/fingerprinting.go b/vendor/github.com/prometheus/common/model/fingerprinting.go deleted file mode 100644 index fc4de41..0000000 --- a/vendor/github.com/prometheus/common/model/fingerprinting.go +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2013 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. - -package model - -import ( - "fmt" - "strconv" -) - -// Fingerprint provides a hash-capable representation of a Metric. -// For our purposes, FNV-1A 64-bit is used. -type Fingerprint uint64 - -// FingerprintFromString transforms a string representation into a Fingerprint. -func FingerprintFromString(s string) (Fingerprint, error) { - num, err := strconv.ParseUint(s, 16, 64) - return Fingerprint(num), err -} - -// ParseFingerprint parses the input string into a fingerprint. -func ParseFingerprint(s string) (Fingerprint, error) { - num, err := strconv.ParseUint(s, 16, 64) - if err != nil { - return 0, err - } - return Fingerprint(num), nil -} - -func (f Fingerprint) String() string { - return fmt.Sprintf("%016x", uint64(f)) -} - -// Fingerprints represents a collection of Fingerprint subject to a given -// natural sorting scheme. It implements sort.Interface. -type Fingerprints []Fingerprint - -// Len implements sort.Interface. -func (f Fingerprints) Len() int { - return len(f) -} - -// Less implements sort.Interface. -func (f Fingerprints) Less(i, j int) bool { - return f[i] < f[j] -} - -// Swap implements sort.Interface. -func (f Fingerprints) Swap(i, j int) { - f[i], f[j] = f[j], f[i] -} - -// FingerprintSet is a set of Fingerprints. -type FingerprintSet map[Fingerprint]struct{} - -// Equal returns true if both sets contain the same elements (and not more). -func (s FingerprintSet) Equal(o FingerprintSet) bool { - if len(s) != len(o) { - return false - } - - for k := range s { - if _, ok := o[k]; !ok { - return false - } - } - - return true -} - -// Intersection returns the elements contained in both sets. -func (s FingerprintSet) Intersection(o FingerprintSet) FingerprintSet { - myLength, otherLength := len(s), len(o) - if myLength == 0 || otherLength == 0 { - return FingerprintSet{} - } - - subSet := s - superSet := o - - if otherLength < myLength { - subSet = o - superSet = s - } - - out := FingerprintSet{} - - for k := range subSet { - if _, ok := superSet[k]; ok { - out[k] = struct{}{} - } - } - - return out -} diff --git a/vendor/github.com/prometheus/common/model/fnv.go b/vendor/github.com/prometheus/common/model/fnv.go deleted file mode 100644 index 038fc1c..0000000 --- a/vendor/github.com/prometheus/common/model/fnv.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2015 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. - -package model - -// Inline and byte-free variant of hash/fnv's fnv64a. - -const ( - offset64 = 14695981039346656037 - prime64 = 1099511628211 -) - -// hashNew initializies a new fnv64a hash value. -func hashNew() uint64 { - return offset64 -} - -// hashAdd adds a string to a fnv64a hash value, returning the updated hash. -func hashAdd(h uint64, s string) uint64 { - for i := 0; i < len(s); i++ { - h ^= uint64(s[i]) - h *= prime64 - } - return h -} - -// hashAddByte adds a byte to a fnv64a hash value, returning the updated hash. -func hashAddByte(h uint64, b byte) uint64 { - h ^= uint64(b) - h *= prime64 - return h -} diff --git a/vendor/github.com/prometheus/common/model/labels.go b/vendor/github.com/prometheus/common/model/labels.go deleted file mode 100644 index 41051a0..0000000 --- a/vendor/github.com/prometheus/common/model/labels.go +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright 2013 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. - -package model - -import ( - "encoding/json" - "fmt" - "regexp" - "strings" - "unicode/utf8" -) - -const ( - // AlertNameLabel is the name of the label containing the an alert's name. - AlertNameLabel = "alertname" - - // ExportedLabelPrefix is the prefix to prepend to the label names present in - // exported metrics if a label of the same name is added by the server. - ExportedLabelPrefix = "exported_" - - // MetricNameLabel is the label name indicating the metric name of a - // timeseries. - MetricNameLabel = "__name__" - - // SchemeLabel is the name of the label that holds the scheme on which to - // scrape a target. - SchemeLabel = "__scheme__" - - // AddressLabel is the name of the label that holds the address of - // a scrape target. - AddressLabel = "__address__" - - // MetricsPathLabel is the name of the label that holds the path on which to - // scrape a target. - MetricsPathLabel = "__metrics_path__" - - // ReservedLabelPrefix is a prefix which is not legal in user-supplied - // label names. - ReservedLabelPrefix = "__" - - // MetaLabelPrefix is a prefix for labels that provide meta information. - // Labels with this prefix are used for intermediate label processing and - // will not be attached to time series. - MetaLabelPrefix = "__meta_" - - // TmpLabelPrefix is a prefix for temporary labels as part of relabelling. - // Labels with this prefix are used for intermediate label processing and - // will not be attached to time series. This is reserved for use in - // Prometheus configuration files by users. - TmpLabelPrefix = "__tmp_" - - // ParamLabelPrefix is a prefix for labels that provide URL parameters - // used to scrape a target. - ParamLabelPrefix = "__param_" - - // JobLabel is the label name indicating the job from which a timeseries - // was scraped. - JobLabel = "job" - - // InstanceLabel is the label name used for the instance label. - InstanceLabel = "instance" - - // BucketLabel is used for the label that defines the upper bound of a - // bucket of a histogram ("le" -> "less or equal"). - BucketLabel = "le" - - // QuantileLabel is used for the label that defines the quantile in a - // summary. - QuantileLabel = "quantile" -) - -// LabelNameRE is a regular expression matching valid label names. Note that the -// IsValid method of LabelName performs the same check but faster than a match -// with this regular expression. -var LabelNameRE = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_]*$") - -// A LabelName is a key for a LabelSet or Metric. It has a value associated -// therewith. -type LabelName string - -// IsValid is true iff the label name matches the pattern of LabelNameRE. This -// method, however, does not use LabelNameRE for the check but a much faster -// hardcoded implementation. -func (ln LabelName) IsValid() bool { - if len(ln) == 0 { - return false - } - for i, b := range ln { - if !((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || b == '_' || (b >= '0' && b <= '9' && i > 0)) { - return false - } - } - return true -} - -// UnmarshalYAML implements the yaml.Unmarshaler interface. -func (ln *LabelName) UnmarshalYAML(unmarshal func(interface{}) error) error { - var s string - if err := unmarshal(&s); err != nil { - return err - } - if !LabelName(s).IsValid() { - return fmt.Errorf("%q is not a valid label name", s) - } - *ln = LabelName(s) - return nil -} - -// UnmarshalJSON implements the json.Unmarshaler interface. -func (ln *LabelName) UnmarshalJSON(b []byte) error { - var s string - if err := json.Unmarshal(b, &s); err != nil { - return err - } - if !LabelName(s).IsValid() { - return fmt.Errorf("%q is not a valid label name", s) - } - *ln = LabelName(s) - return nil -} - -// LabelNames is a sortable LabelName slice. In implements sort.Interface. -type LabelNames []LabelName - -func (l LabelNames) Len() int { - return len(l) -} - -func (l LabelNames) Less(i, j int) bool { - return l[i] < l[j] -} - -func (l LabelNames) Swap(i, j int) { - l[i], l[j] = l[j], l[i] -} - -func (l LabelNames) String() string { - labelStrings := make([]string, 0, len(l)) - for _, label := range l { - labelStrings = append(labelStrings, string(label)) - } - return strings.Join(labelStrings, ", ") -} - -// A LabelValue is an associated value for a LabelName. -type LabelValue string - -// IsValid returns true iff the string is a valid UTF8. -func (lv LabelValue) IsValid() bool { - return utf8.ValidString(string(lv)) -} - -// LabelValues is a sortable LabelValue slice. It implements sort.Interface. -type LabelValues []LabelValue - -func (l LabelValues) Len() int { - return len(l) -} - -func (l LabelValues) Less(i, j int) bool { - return string(l[i]) < string(l[j]) -} - -func (l LabelValues) Swap(i, j int) { - l[i], l[j] = l[j], l[i] -} - -// LabelPair pairs a name with a value. -type LabelPair struct { - Name LabelName - Value LabelValue -} - -// LabelPairs is a sortable slice of LabelPair pointers. It implements -// sort.Interface. -type LabelPairs []*LabelPair - -func (l LabelPairs) Len() int { - return len(l) -} - -func (l LabelPairs) Less(i, j int) bool { - switch { - case l[i].Name > l[j].Name: - return false - case l[i].Name < l[j].Name: - return true - case l[i].Value > l[j].Value: - return false - case l[i].Value < l[j].Value: - return true - default: - return false - } -} - -func (l LabelPairs) Swap(i, j int) { - l[i], l[j] = l[j], l[i] -} diff --git a/vendor/github.com/prometheus/common/model/labelset.go b/vendor/github.com/prometheus/common/model/labelset.go deleted file mode 100644 index 6eda08a..0000000 --- a/vendor/github.com/prometheus/common/model/labelset.go +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright 2013 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. - -package model - -import ( - "encoding/json" - "fmt" - "sort" - "strings" -) - -// A LabelSet is a collection of LabelName and LabelValue pairs. The LabelSet -// may be fully-qualified down to the point where it may resolve to a single -// Metric in the data store or not. All operations that occur within the realm -// of a LabelSet can emit a vector of Metric entities to which the LabelSet may -// match. -type LabelSet map[LabelName]LabelValue - -// Validate checks whether all names and values in the label set -// are valid. -func (ls LabelSet) Validate() error { - for ln, lv := range ls { - if !ln.IsValid() { - return fmt.Errorf("invalid name %q", ln) - } - if !lv.IsValid() { - return fmt.Errorf("invalid value %q", lv) - } - } - return nil -} - -// Equal returns true iff both label sets have exactly the same key/value pairs. -func (ls LabelSet) Equal(o LabelSet) bool { - if len(ls) != len(o) { - return false - } - for ln, lv := range ls { - olv, ok := o[ln] - if !ok { - return false - } - if olv != lv { - return false - } - } - return true -} - -// Before compares the metrics, using the following criteria: -// -// If m has fewer labels than o, it is before o. If it has more, it is not. -// -// If the number of labels is the same, the superset of all label names is -// sorted alphanumerically. The first differing label pair found in that order -// determines the outcome: If the label does not exist at all in m, then m is -// before o, and vice versa. Otherwise the label value is compared -// alphanumerically. -// -// If m and o are equal, the method returns false. -func (ls LabelSet) Before(o LabelSet) bool { - if len(ls) < len(o) { - return true - } - if len(ls) > len(o) { - return false - } - - lns := make(LabelNames, 0, len(ls)+len(o)) - for ln := range ls { - lns = append(lns, ln) - } - for ln := range o { - lns = append(lns, ln) - } - // It's probably not worth it to de-dup lns. - sort.Sort(lns) - for _, ln := range lns { - mlv, ok := ls[ln] - if !ok { - return true - } - olv, ok := o[ln] - if !ok { - return false - } - if mlv < olv { - return true - } - if mlv > olv { - return false - } - } - return false -} - -// Clone returns a copy of the label set. -func (ls LabelSet) Clone() LabelSet { - lsn := make(LabelSet, len(ls)) - for ln, lv := range ls { - lsn[ln] = lv - } - return lsn -} - -// Merge is a helper function to non-destructively merge two label sets. -func (l LabelSet) Merge(other LabelSet) LabelSet { - result := make(LabelSet, len(l)) - - for k, v := range l { - result[k] = v - } - - for k, v := range other { - result[k] = v - } - - return result -} - -func (l LabelSet) String() string { - lstrs := make([]string, 0, len(l)) - for l, v := range l { - lstrs = append(lstrs, fmt.Sprintf("%s=%q", l, v)) - } - - sort.Strings(lstrs) - return fmt.Sprintf("{%s}", strings.Join(lstrs, ", ")) -} - -// Fingerprint returns the LabelSet's fingerprint. -func (ls LabelSet) Fingerprint() Fingerprint { - return labelSetToFingerprint(ls) -} - -// FastFingerprint returns the LabelSet's Fingerprint calculated by a faster hashing -// algorithm, which is, however, more susceptible to hash collisions. -func (ls LabelSet) FastFingerprint() Fingerprint { - return labelSetToFastFingerprint(ls) -} - -// UnmarshalJSON implements the json.Unmarshaler interface. -func (l *LabelSet) UnmarshalJSON(b []byte) error { - var m map[LabelName]LabelValue - if err := json.Unmarshal(b, &m); err != nil { - return err - } - // encoding/json only unmarshals maps of the form map[string]T. It treats - // LabelName as a string and does not call its UnmarshalJSON method. - // Thus, we have to replicate the behavior here. - for ln := range m { - if !ln.IsValid() { - return fmt.Errorf("%q is not a valid label name", ln) - } - } - *l = LabelSet(m) - return nil -} diff --git a/vendor/github.com/prometheus/common/model/metric.go b/vendor/github.com/prometheus/common/model/metric.go deleted file mode 100644 index f725090..0000000 --- a/vendor/github.com/prometheus/common/model/metric.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2013 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. - -package model - -import ( - "fmt" - "regexp" - "sort" - "strings" -) - -var ( - separator = []byte{0} - // MetricNameRE is a regular expression matching valid metric - // names. Note that the IsValidMetricName function performs the same - // check but faster than a match with this regular expression. - MetricNameRE = regexp.MustCompile(`^[a-zA-Z_:][a-zA-Z0-9_:]*$`) -) - -// A Metric is similar to a LabelSet, but the key difference is that a Metric is -// a singleton and refers to one and only one stream of samples. -type Metric LabelSet - -// Equal compares the metrics. -func (m Metric) Equal(o Metric) bool { - return LabelSet(m).Equal(LabelSet(o)) -} - -// Before compares the metrics' underlying label sets. -func (m Metric) Before(o Metric) bool { - return LabelSet(m).Before(LabelSet(o)) -} - -// Clone returns a copy of the Metric. -func (m Metric) Clone() Metric { - clone := make(Metric, len(m)) - for k, v := range m { - clone[k] = v - } - return clone -} - -func (m Metric) String() string { - metricName, hasName := m[MetricNameLabel] - numLabels := len(m) - 1 - if !hasName { - numLabels = len(m) - } - labelStrings := make([]string, 0, numLabels) - for label, value := range m { - if label != MetricNameLabel { - labelStrings = append(labelStrings, fmt.Sprintf("%s=%q", label, value)) - } - } - - switch numLabels { - case 0: - if hasName { - return string(metricName) - } - return "{}" - default: - sort.Strings(labelStrings) - return fmt.Sprintf("%s{%s}", metricName, strings.Join(labelStrings, ", ")) - } -} - -// Fingerprint returns a Metric's Fingerprint. -func (m Metric) Fingerprint() Fingerprint { - return LabelSet(m).Fingerprint() -} - -// FastFingerprint returns a Metric's Fingerprint calculated by a faster hashing -// algorithm, which is, however, more susceptible to hash collisions. -func (m Metric) FastFingerprint() Fingerprint { - return LabelSet(m).FastFingerprint() -} - -// IsValidMetricName returns true iff name matches the pattern of MetricNameRE. -// This function, however, does not use MetricNameRE for the check but a much -// faster hardcoded implementation. -func IsValidMetricName(n LabelValue) bool { - if len(n) == 0 { - return false - } - for i, b := range n { - if !((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || b == '_' || b == ':' || (b >= '0' && b <= '9' && i > 0)) { - return false - } - } - return true -} diff --git a/vendor/github.com/prometheus/common/model/model.go b/vendor/github.com/prometheus/common/model/model.go deleted file mode 100644 index a7b9691..0000000 --- a/vendor/github.com/prometheus/common/model/model.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2013 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. - -// Package model contains common data structures that are shared across -// Prometheus components and libraries. -package model diff --git a/vendor/github.com/prometheus/common/model/signature.go b/vendor/github.com/prometheus/common/model/signature.go deleted file mode 100644 index 8762b13..0000000 --- a/vendor/github.com/prometheus/common/model/signature.go +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright 2014 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. - -package model - -import ( - "sort" -) - -// SeparatorByte is a byte that cannot occur in valid UTF-8 sequences and is -// used to separate label names, label values, and other strings from each other -// when calculating their combined hash value (aka signature aka fingerprint). -const SeparatorByte byte = 255 - -var ( - // cache the signature of an empty label set. - emptyLabelSignature = hashNew() -) - -// LabelsToSignature returns a quasi-unique signature (i.e., fingerprint) for a -// given label set. (Collisions are possible but unlikely if the number of label -// sets the function is applied to is small.) -func LabelsToSignature(labels map[string]string) uint64 { - if len(labels) == 0 { - return emptyLabelSignature - } - - labelNames := make([]string, 0, len(labels)) - for labelName := range labels { - labelNames = append(labelNames, labelName) - } - sort.Strings(labelNames) - - sum := hashNew() - for _, labelName := range labelNames { - sum = hashAdd(sum, labelName) - sum = hashAddByte(sum, SeparatorByte) - sum = hashAdd(sum, labels[labelName]) - sum = hashAddByte(sum, SeparatorByte) - } - return sum -} - -// labelSetToFingerprint works exactly as LabelsToSignature but takes a LabelSet as -// parameter (rather than a label map) and returns a Fingerprint. -func labelSetToFingerprint(ls LabelSet) Fingerprint { - if len(ls) == 0 { - return Fingerprint(emptyLabelSignature) - } - - labelNames := make(LabelNames, 0, len(ls)) - for labelName := range ls { - labelNames = append(labelNames, labelName) - } - sort.Sort(labelNames) - - sum := hashNew() - for _, labelName := range labelNames { - sum = hashAdd(sum, string(labelName)) - sum = hashAddByte(sum, SeparatorByte) - sum = hashAdd(sum, string(ls[labelName])) - sum = hashAddByte(sum, SeparatorByte) - } - return Fingerprint(sum) -} - -// labelSetToFastFingerprint works similar to labelSetToFingerprint but uses a -// faster and less allocation-heavy hash function, which is more susceptible to -// create hash collisions. Therefore, collision detection should be applied. -func labelSetToFastFingerprint(ls LabelSet) Fingerprint { - if len(ls) == 0 { - return Fingerprint(emptyLabelSignature) - } - - var result uint64 - for labelName, labelValue := range ls { - sum := hashNew() - sum = hashAdd(sum, string(labelName)) - sum = hashAddByte(sum, SeparatorByte) - sum = hashAdd(sum, string(labelValue)) - result ^= sum - } - return Fingerprint(result) -} - -// SignatureForLabels works like LabelsToSignature but takes a Metric as -// parameter (rather than a label map) and only includes the labels with the -// specified LabelNames into the signature calculation. The labels passed in -// will be sorted by this function. -func SignatureForLabels(m Metric, labels ...LabelName) uint64 { - if len(labels) == 0 { - return emptyLabelSignature - } - - sort.Sort(LabelNames(labels)) - - sum := hashNew() - for _, label := range labels { - sum = hashAdd(sum, string(label)) - sum = hashAddByte(sum, SeparatorByte) - sum = hashAdd(sum, string(m[label])) - sum = hashAddByte(sum, SeparatorByte) - } - return sum -} - -// SignatureWithoutLabels works like LabelsToSignature but takes a Metric as -// parameter (rather than a label map) and excludes the labels with any of the -// specified LabelNames from the signature calculation. -func SignatureWithoutLabels(m Metric, labels map[LabelName]struct{}) uint64 { - if len(m) == 0 { - return emptyLabelSignature - } - - labelNames := make(LabelNames, 0, len(m)) - for labelName := range m { - if _, exclude := labels[labelName]; !exclude { - labelNames = append(labelNames, labelName) - } - } - if len(labelNames) == 0 { - return emptyLabelSignature - } - sort.Sort(labelNames) - - sum := hashNew() - for _, labelName := range labelNames { - sum = hashAdd(sum, string(labelName)) - sum = hashAddByte(sum, SeparatorByte) - sum = hashAdd(sum, string(m[labelName])) - sum = hashAddByte(sum, SeparatorByte) - } - return sum -} diff --git a/vendor/github.com/prometheus/common/model/silence.go b/vendor/github.com/prometheus/common/model/silence.go deleted file mode 100644 index 7538e29..0000000 --- a/vendor/github.com/prometheus/common/model/silence.go +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2015 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. - -package model - -import ( - "encoding/json" - "fmt" - "regexp" - "time" -) - -// Matcher describes a matches the value of a given label. -type Matcher struct { - Name LabelName `json:"name"` - Value string `json:"value"` - IsRegex bool `json:"isRegex"` -} - -func (m *Matcher) UnmarshalJSON(b []byte) error { - type plain Matcher - if err := json.Unmarshal(b, (*plain)(m)); err != nil { - return err - } - - if len(m.Name) == 0 { - return fmt.Errorf("label name in matcher must not be empty") - } - if m.IsRegex { - if _, err := regexp.Compile(m.Value); err != nil { - return err - } - } - return nil -} - -// Validate returns true iff all fields of the matcher have valid values. -func (m *Matcher) Validate() error { - if !m.Name.IsValid() { - return fmt.Errorf("invalid name %q", m.Name) - } - if m.IsRegex { - if _, err := regexp.Compile(m.Value); err != nil { - return fmt.Errorf("invalid regular expression %q", m.Value) - } - } else if !LabelValue(m.Value).IsValid() || len(m.Value) == 0 { - return fmt.Errorf("invalid value %q", m.Value) - } - return nil -} - -// Silence defines the representation of a silence definiton -// in the Prometheus eco-system. -type Silence struct { - ID uint64 `json:"id,omitempty"` - - Matchers []*Matcher `json:"matchers"` - - StartsAt time.Time `json:"startsAt"` - EndsAt time.Time `json:"endsAt"` - - CreatedAt time.Time `json:"createdAt,omitempty"` - CreatedBy string `json:"createdBy"` - Comment string `json:"comment,omitempty"` -} - -// Validate returns true iff all fields of the silence have valid values. -func (s *Silence) Validate() error { - if len(s.Matchers) == 0 { - return fmt.Errorf("at least one matcher required") - } - for _, m := range s.Matchers { - if err := m.Validate(); err != nil { - return fmt.Errorf("invalid matcher: %s", err) - } - } - if s.StartsAt.IsZero() { - return fmt.Errorf("start time missing") - } - if s.EndsAt.IsZero() { - return fmt.Errorf("end time missing") - } - if s.EndsAt.Before(s.StartsAt) { - return fmt.Errorf("start time must be before end time") - } - if s.CreatedBy == "" { - return fmt.Errorf("creator information missing") - } - if s.Comment == "" { - return fmt.Errorf("comment missing") - } - if s.CreatedAt.IsZero() { - return fmt.Errorf("creation timestamp missing") - } - return nil -} diff --git a/vendor/github.com/prometheus/common/model/time.go b/vendor/github.com/prometheus/common/model/time.go deleted file mode 100644 index 74ed5a9..0000000 --- a/vendor/github.com/prometheus/common/model/time.go +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright 2013 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. - -package model - -import ( - "fmt" - "math" - "regexp" - "strconv" - "strings" - "time" -) - -const ( - // MinimumTick is the minimum supported time resolution. This has to be - // at least time.Second in order for the code below to work. - minimumTick = time.Millisecond - // second is the Time duration equivalent to one second. - second = int64(time.Second / minimumTick) - // The number of nanoseconds per minimum tick. - nanosPerTick = int64(minimumTick / time.Nanosecond) - - // Earliest is the earliest Time representable. Handy for - // initializing a high watermark. - Earliest = Time(math.MinInt64) - // Latest is the latest Time representable. Handy for initializing - // a low watermark. - Latest = Time(math.MaxInt64) -) - -// Time is the number of milliseconds since the epoch -// (1970-01-01 00:00 UTC) excluding leap seconds. -type Time int64 - -// Interval describes and interval between two timestamps. -type Interval struct { - Start, End Time -} - -// Now returns the current time as a Time. -func Now() Time { - return TimeFromUnixNano(time.Now().UnixNano()) -} - -// TimeFromUnix returns the Time equivalent to the Unix Time t -// provided in seconds. -func TimeFromUnix(t int64) Time { - return Time(t * second) -} - -// TimeFromUnixNano returns the Time equivalent to the Unix Time -// t provided in nanoseconds. -func TimeFromUnixNano(t int64) Time { - return Time(t / nanosPerTick) -} - -// Equal reports whether two Times represent the same instant. -func (t Time) Equal(o Time) bool { - return t == o -} - -// Before reports whether the Time t is before o. -func (t Time) Before(o Time) bool { - return t < o -} - -// After reports whether the Time t is after o. -func (t Time) After(o Time) bool { - return t > o -} - -// Add returns the Time t + d. -func (t Time) Add(d time.Duration) Time { - return t + Time(d/minimumTick) -} - -// Sub returns the Duration t - o. -func (t Time) Sub(o Time) time.Duration { - return time.Duration(t-o) * minimumTick -} - -// Time returns the time.Time representation of t. -func (t Time) Time() time.Time { - return time.Unix(int64(t)/second, (int64(t)%second)*nanosPerTick) -} - -// Unix returns t as a Unix time, the number of seconds elapsed -// since January 1, 1970 UTC. -func (t Time) Unix() int64 { - return int64(t) / second -} - -// UnixNano returns t as a Unix time, the number of nanoseconds elapsed -// since January 1, 1970 UTC. -func (t Time) UnixNano() int64 { - return int64(t) * nanosPerTick -} - -// The number of digits after the dot. -var dotPrecision = int(math.Log10(float64(second))) - -// String returns a string representation of the Time. -func (t Time) String() string { - return strconv.FormatFloat(float64(t)/float64(second), 'f', -1, 64) -} - -// MarshalJSON implements the json.Marshaler interface. -func (t Time) MarshalJSON() ([]byte, error) { - return []byte(t.String()), nil -} - -// UnmarshalJSON implements the json.Unmarshaler interface. -func (t *Time) UnmarshalJSON(b []byte) error { - p := strings.Split(string(b), ".") - switch len(p) { - case 1: - v, err := strconv.ParseInt(string(p[0]), 10, 64) - if err != nil { - return err - } - *t = Time(v * second) - - case 2: - v, err := strconv.ParseInt(string(p[0]), 10, 64) - if err != nil { - return err - } - v *= second - - prec := dotPrecision - len(p[1]) - if prec < 0 { - p[1] = p[1][:dotPrecision] - } else if prec > 0 { - p[1] = p[1] + strings.Repeat("0", prec) - } - - va, err := strconv.ParseInt(p[1], 10, 32) - if err != nil { - return err - } - - *t = Time(v + va) - - default: - return fmt.Errorf("invalid time %q", string(b)) - } - return nil -} - -// Duration wraps time.Duration. It is used to parse the custom duration format -// from YAML. -// This type should not propagate beyond the scope of input/output processing. -type Duration time.Duration - -// Set implements pflag/flag.Value -func (d *Duration) Set(s string) error { - var err error - *d, err = ParseDuration(s) - return err -} - -// Type implements pflag.Value -func (d *Duration) Type() string { - return "duration" -} - -var durationRE = regexp.MustCompile("^([0-9]+)(y|w|d|h|m|s|ms)$") - -// ParseDuration parses a string into a time.Duration, assuming that a year -// always has 365d, a week always has 7d, and a day always has 24h. -func ParseDuration(durationStr string) (Duration, error) { - matches := durationRE.FindStringSubmatch(durationStr) - if len(matches) != 3 { - return 0, fmt.Errorf("not a valid duration string: %q", durationStr) - } - var ( - n, _ = strconv.Atoi(matches[1]) - dur = time.Duration(n) * time.Millisecond - ) - switch unit := matches[2]; unit { - case "y": - dur *= 1000 * 60 * 60 * 24 * 365 - case "w": - dur *= 1000 * 60 * 60 * 24 * 7 - case "d": - dur *= 1000 * 60 * 60 * 24 - case "h": - dur *= 1000 * 60 * 60 - case "m": - dur *= 1000 * 60 - case "s": - dur *= 1000 - case "ms": - // Value already correct - default: - return 0, fmt.Errorf("invalid time unit in duration string: %q", unit) - } - return Duration(dur), nil -} - -func (d Duration) String() string { - var ( - ms = int64(time.Duration(d) / time.Millisecond) - unit = "ms" - ) - if ms == 0 { - return "0s" - } - factors := map[string]int64{ - "y": 1000 * 60 * 60 * 24 * 365, - "w": 1000 * 60 * 60 * 24 * 7, - "d": 1000 * 60 * 60 * 24, - "h": 1000 * 60 * 60, - "m": 1000 * 60, - "s": 1000, - "ms": 1, - } - - switch int64(0) { - case ms % factors["y"]: - unit = "y" - case ms % factors["w"]: - unit = "w" - case ms % factors["d"]: - unit = "d" - case ms % factors["h"]: - unit = "h" - case ms % factors["m"]: - unit = "m" - case ms % factors["s"]: - unit = "s" - } - return fmt.Sprintf("%v%v", ms/factors[unit], unit) -} - -// MarshalYAML implements the yaml.Marshaler interface. -func (d Duration) MarshalYAML() (interface{}, error) { - return d.String(), nil -} - -// UnmarshalYAML implements the yaml.Unmarshaler interface. -func (d *Duration) UnmarshalYAML(unmarshal func(interface{}) error) error { - var s string - if err := unmarshal(&s); err != nil { - return err - } - dur, err := ParseDuration(s) - if err != nil { - return err - } - *d = dur - return nil -} diff --git a/vendor/github.com/prometheus/common/model/value.go b/vendor/github.com/prometheus/common/model/value.go deleted file mode 100644 index c9ed3ff..0000000 --- a/vendor/github.com/prometheus/common/model/value.go +++ /dev/null @@ -1,416 +0,0 @@ -// Copyright 2013 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. - -package model - -import ( - "encoding/json" - "fmt" - "math" - "sort" - "strconv" - "strings" -) - -var ( - // ZeroSamplePair is the pseudo zero-value of SamplePair used to signal a - // non-existing sample pair. It is a SamplePair with timestamp Earliest and - // value 0.0. Note that the natural zero value of SamplePair has a timestamp - // of 0, which is possible to appear in a real SamplePair and thus not - // suitable to signal a non-existing SamplePair. - ZeroSamplePair = SamplePair{Timestamp: Earliest} - - // ZeroSample is the pseudo zero-value of Sample used to signal a - // non-existing sample. It is a Sample with timestamp Earliest, value 0.0, - // and metric nil. Note that the natural zero value of Sample has a timestamp - // of 0, which is possible to appear in a real Sample and thus not suitable - // to signal a non-existing Sample. - ZeroSample = Sample{Timestamp: Earliest} -) - -// A SampleValue is a representation of a value for a given sample at a given -// time. -type SampleValue float64 - -// MarshalJSON implements json.Marshaler. -func (v SampleValue) MarshalJSON() ([]byte, error) { - return json.Marshal(v.String()) -} - -// UnmarshalJSON implements json.Unmarshaler. -func (v *SampleValue) UnmarshalJSON(b []byte) error { - if len(b) < 2 || b[0] != '"' || b[len(b)-1] != '"' { - return fmt.Errorf("sample value must be a quoted string") - } - f, err := strconv.ParseFloat(string(b[1:len(b)-1]), 64) - if err != nil { - return err - } - *v = SampleValue(f) - return nil -} - -// Equal returns true if the value of v and o is equal or if both are NaN. Note -// that v==o is false if both are NaN. If you want the conventional float -// behavior, use == to compare two SampleValues. -func (v SampleValue) Equal(o SampleValue) bool { - if v == o { - return true - } - return math.IsNaN(float64(v)) && math.IsNaN(float64(o)) -} - -func (v SampleValue) String() string { - return strconv.FormatFloat(float64(v), 'f', -1, 64) -} - -// SamplePair pairs a SampleValue with a Timestamp. -type SamplePair struct { - Timestamp Time - Value SampleValue -} - -// MarshalJSON implements json.Marshaler. -func (s SamplePair) MarshalJSON() ([]byte, error) { - t, err := json.Marshal(s.Timestamp) - if err != nil { - return nil, err - } - v, err := json.Marshal(s.Value) - if err != nil { - return nil, err - } - return []byte(fmt.Sprintf("[%s,%s]", t, v)), nil -} - -// UnmarshalJSON implements json.Unmarshaler. -func (s *SamplePair) UnmarshalJSON(b []byte) error { - v := [...]json.Unmarshaler{&s.Timestamp, &s.Value} - return json.Unmarshal(b, &v) -} - -// Equal returns true if this SamplePair and o have equal Values and equal -// Timestamps. The sematics of Value equality is defined by SampleValue.Equal. -func (s *SamplePair) Equal(o *SamplePair) bool { - return s == o || (s.Value.Equal(o.Value) && s.Timestamp.Equal(o.Timestamp)) -} - -func (s SamplePair) String() string { - return fmt.Sprintf("%s @[%s]", s.Value, s.Timestamp) -} - -// Sample is a sample pair associated with a metric. -type Sample struct { - Metric Metric `json:"metric"` - Value SampleValue `json:"value"` - Timestamp Time `json:"timestamp"` -} - -// Equal compares first the metrics, then the timestamp, then the value. The -// sematics of value equality is defined by SampleValue.Equal. -func (s *Sample) Equal(o *Sample) bool { - if s == o { - return true - } - - if !s.Metric.Equal(o.Metric) { - return false - } - if !s.Timestamp.Equal(o.Timestamp) { - return false - } - - return s.Value.Equal(o.Value) -} - -func (s Sample) String() string { - return fmt.Sprintf("%s => %s", s.Metric, SamplePair{ - Timestamp: s.Timestamp, - Value: s.Value, - }) -} - -// MarshalJSON implements json.Marshaler. -func (s Sample) MarshalJSON() ([]byte, error) { - v := struct { - Metric Metric `json:"metric"` - Value SamplePair `json:"value"` - }{ - Metric: s.Metric, - Value: SamplePair{ - Timestamp: s.Timestamp, - Value: s.Value, - }, - } - - return json.Marshal(&v) -} - -// UnmarshalJSON implements json.Unmarshaler. -func (s *Sample) UnmarshalJSON(b []byte) error { - v := struct { - Metric Metric `json:"metric"` - Value SamplePair `json:"value"` - }{ - Metric: s.Metric, - Value: SamplePair{ - Timestamp: s.Timestamp, - Value: s.Value, - }, - } - - if err := json.Unmarshal(b, &v); err != nil { - return err - } - - s.Metric = v.Metric - s.Timestamp = v.Value.Timestamp - s.Value = v.Value.Value - - return nil -} - -// Samples is a sortable Sample slice. It implements sort.Interface. -type Samples []*Sample - -func (s Samples) Len() int { - return len(s) -} - -// Less compares first the metrics, then the timestamp. -func (s Samples) Less(i, j int) bool { - switch { - case s[i].Metric.Before(s[j].Metric): - return true - case s[j].Metric.Before(s[i].Metric): - return false - case s[i].Timestamp.Before(s[j].Timestamp): - return true - default: - return false - } -} - -func (s Samples) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -// Equal compares two sets of samples and returns true if they are equal. -func (s Samples) Equal(o Samples) bool { - if len(s) != len(o) { - return false - } - - for i, sample := range s { - if !sample.Equal(o[i]) { - return false - } - } - return true -} - -// SampleStream is a stream of Values belonging to an attached COWMetric. -type SampleStream struct { - Metric Metric `json:"metric"` - Values []SamplePair `json:"values"` -} - -func (ss SampleStream) String() string { - vals := make([]string, len(ss.Values)) - for i, v := range ss.Values { - vals[i] = v.String() - } - return fmt.Sprintf("%s =>\n%s", ss.Metric, strings.Join(vals, "\n")) -} - -// Value is a generic interface for values resulting from a query evaluation. -type Value interface { - Type() ValueType - String() string -} - -func (Matrix) Type() ValueType { return ValMatrix } -func (Vector) Type() ValueType { return ValVector } -func (*Scalar) Type() ValueType { return ValScalar } -func (*String) Type() ValueType { return ValString } - -type ValueType int - -const ( - ValNone ValueType = iota - ValScalar - ValVector - ValMatrix - ValString -) - -// MarshalJSON implements json.Marshaler. -func (et ValueType) MarshalJSON() ([]byte, error) { - return json.Marshal(et.String()) -} - -func (et *ValueType) UnmarshalJSON(b []byte) error { - var s string - if err := json.Unmarshal(b, &s); err != nil { - return err - } - switch s { - case "": - *et = ValNone - case "scalar": - *et = ValScalar - case "vector": - *et = ValVector - case "matrix": - *et = ValMatrix - case "string": - *et = ValString - default: - return fmt.Errorf("unknown value type %q", s) - } - return nil -} - -func (e ValueType) String() string { - switch e { - case ValNone: - return "" - case ValScalar: - return "scalar" - case ValVector: - return "vector" - case ValMatrix: - return "matrix" - case ValString: - return "string" - } - panic("ValueType.String: unhandled value type") -} - -// Scalar is a scalar value evaluated at the set timestamp. -type Scalar struct { - Value SampleValue `json:"value"` - Timestamp Time `json:"timestamp"` -} - -func (s Scalar) String() string { - return fmt.Sprintf("scalar: %v @[%v]", s.Value, s.Timestamp) -} - -// MarshalJSON implements json.Marshaler. -func (s Scalar) MarshalJSON() ([]byte, error) { - v := strconv.FormatFloat(float64(s.Value), 'f', -1, 64) - return json.Marshal([...]interface{}{s.Timestamp, string(v)}) -} - -// UnmarshalJSON implements json.Unmarshaler. -func (s *Scalar) UnmarshalJSON(b []byte) error { - var f string - v := [...]interface{}{&s.Timestamp, &f} - - if err := json.Unmarshal(b, &v); err != nil { - return err - } - - value, err := strconv.ParseFloat(f, 64) - if err != nil { - return fmt.Errorf("error parsing sample value: %s", err) - } - s.Value = SampleValue(value) - return nil -} - -// String is a string value evaluated at the set timestamp. -type String struct { - Value string `json:"value"` - Timestamp Time `json:"timestamp"` -} - -func (s *String) String() string { - return s.Value -} - -// MarshalJSON implements json.Marshaler. -func (s String) MarshalJSON() ([]byte, error) { - return json.Marshal([]interface{}{s.Timestamp, s.Value}) -} - -// UnmarshalJSON implements json.Unmarshaler. -func (s *String) UnmarshalJSON(b []byte) error { - v := [...]interface{}{&s.Timestamp, &s.Value} - return json.Unmarshal(b, &v) -} - -// Vector is basically only an alias for Samples, but the -// contract is that in a Vector, all Samples have the same timestamp. -type Vector []*Sample - -func (vec Vector) String() string { - entries := make([]string, len(vec)) - for i, s := range vec { - entries[i] = s.String() - } - return strings.Join(entries, "\n") -} - -func (vec Vector) Len() int { return len(vec) } -func (vec Vector) Swap(i, j int) { vec[i], vec[j] = vec[j], vec[i] } - -// Less compares first the metrics, then the timestamp. -func (vec Vector) Less(i, j int) bool { - switch { - case vec[i].Metric.Before(vec[j].Metric): - return true - case vec[j].Metric.Before(vec[i].Metric): - return false - case vec[i].Timestamp.Before(vec[j].Timestamp): - return true - default: - return false - } -} - -// Equal compares two sets of samples and returns true if they are equal. -func (vec Vector) Equal(o Vector) bool { - if len(vec) != len(o) { - return false - } - - for i, sample := range vec { - if !sample.Equal(o[i]) { - return false - } - } - return true -} - -// Matrix is a list of time series. -type Matrix []*SampleStream - -func (m Matrix) Len() int { return len(m) } -func (m Matrix) Less(i, j int) bool { return m[i].Metric.Before(m[j].Metric) } -func (m Matrix) Swap(i, j int) { m[i], m[j] = m[j], m[i] } - -func (mat Matrix) String() string { - matCp := make(Matrix, len(mat)) - copy(matCp, mat) - sort.Sort(matCp) - - strs := make([]string, len(matCp)) - - for i, ss := range matCp { - strs[i] = ss.String() - } - - return strings.Join(strs, "\n") -} diff --git a/vendor/github.com/prometheus/procfs/.travis.yml b/vendor/github.com/prometheus/procfs/.travis.yml deleted file mode 100644 index 0dc4212..0000000 --- a/vendor/github.com/prometheus/procfs/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -sudo: false - -language: go - -go: -- 1.9.x -- 1.x - -go_import_path: github.com/prometheus/procfs diff --git a/vendor/github.com/prometheus/procfs/CONTRIBUTING.md b/vendor/github.com/prometheus/procfs/CONTRIBUTING.md deleted file mode 100644 index 40503ed..0000000 --- a/vendor/github.com/prometheus/procfs/CONTRIBUTING.md +++ /dev/null @@ -1,18 +0,0 @@ -# Contributing - -Prometheus uses GitHub to manage reviews of pull requests. - -* If you have a trivial fix or improvement, go ahead and create a pull request, - addressing (with `@...`) the maintainer of this repository (see - [MAINTAINERS.md](MAINTAINERS.md)) in the description of the pull request. - -* If you plan to do something more involved, first discuss your ideas - on our [mailing list](https://groups.google.com/forum/?fromgroups#!forum/prometheus-developers). - This will avoid unnecessary work and surely give you and us a good deal - of inspiration. - -* Relevant coding style guidelines are the [Go Code Review - Comments](https://code.google.com/p/go-wiki/wiki/CodeReviewComments) - and the _Formatting and style_ section of Peter Bourgon's [Go: Best - Practices for Production - Environments](http://peter.bourgon.org/go-in-production/#formatting-and-style). diff --git a/vendor/github.com/prometheus/procfs/LICENSE b/vendor/github.com/prometheus/procfs/LICENSE deleted file mode 100644 index 261eeb9..0000000 --- a/vendor/github.com/prometheus/procfs/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. diff --git a/vendor/github.com/prometheus/procfs/MAINTAINERS.md b/vendor/github.com/prometheus/procfs/MAINTAINERS.md deleted file mode 100644 index 35993c4..0000000 --- a/vendor/github.com/prometheus/procfs/MAINTAINERS.md +++ /dev/null @@ -1 +0,0 @@ -* Tobias Schmidt diff --git a/vendor/github.com/prometheus/procfs/Makefile b/vendor/github.com/prometheus/procfs/Makefile deleted file mode 100644 index dd48afd..0000000 --- a/vendor/github.com/prometheus/procfs/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -ci: fmt lint test - -fmt: - ! gofmt -l *.go | read nothing - go vet - -lint: - go get github.com/golang/lint/golint - golint *.go - -test: sysfs/fixtures/.unpacked - go test -v ./... - -sysfs/fixtures/.unpacked: sysfs/fixtures.ttar - ./ttar -C sysfs -x -f sysfs/fixtures.ttar - touch $@ - -.PHONY: fmt lint test ci diff --git a/vendor/github.com/prometheus/procfs/NOTICE b/vendor/github.com/prometheus/procfs/NOTICE deleted file mode 100644 index 53c5e9a..0000000 --- a/vendor/github.com/prometheus/procfs/NOTICE +++ /dev/null @@ -1,7 +0,0 @@ -procfs provides functions to retrieve system, kernel and process -metrics from the pseudo-filesystem proc. - -Copyright 2014-2015 The Prometheus Authors - -This product includes software developed at -SoundCloud Ltd. (http://soundcloud.com/). diff --git a/vendor/github.com/prometheus/procfs/README.md b/vendor/github.com/prometheus/procfs/README.md deleted file mode 100644 index 2095494..0000000 --- a/vendor/github.com/prometheus/procfs/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# procfs - -This procfs package provides functions to retrieve system, kernel and process -metrics from the pseudo-filesystem proc. - -*WARNING*: This package is a work in progress. Its API may still break in -backwards-incompatible ways without warnings. Use it at your own risk. - -[![GoDoc](https://godoc.org/github.com/prometheus/procfs?status.png)](https://godoc.org/github.com/prometheus/procfs) -[![Build Status](https://travis-ci.org/prometheus/procfs.svg?branch=master)](https://travis-ci.org/prometheus/procfs) -[![Go Report Card](https://goreportcard.com/badge/github.com/prometheus/procfs)](https://goreportcard.com/report/github.com/prometheus/procfs) diff --git a/vendor/github.com/prometheus/procfs/buddyinfo.go b/vendor/github.com/prometheus/procfs/buddyinfo.go deleted file mode 100644 index d3a8268..0000000 --- a/vendor/github.com/prometheus/procfs/buddyinfo.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2017 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. - -package procfs - -import ( - "bufio" - "fmt" - "io" - "os" - "strconv" - "strings" -) - -// A BuddyInfo is the details parsed from /proc/buddyinfo. -// The data is comprised of an array of free fragments of each size. -// The sizes are 2^n*PAGE_SIZE, where n is the array index. -type BuddyInfo struct { - Node string - Zone string - Sizes []float64 -} - -// NewBuddyInfo reads the buddyinfo statistics. -func NewBuddyInfo() ([]BuddyInfo, error) { - fs, err := NewFS(DefaultMountPoint) - if err != nil { - return nil, err - } - - return fs.NewBuddyInfo() -} - -// NewBuddyInfo reads the buddyinfo statistics from the specified `proc` filesystem. -func (fs FS) NewBuddyInfo() ([]BuddyInfo, error) { - file, err := os.Open(fs.Path("buddyinfo")) - if err != nil { - return nil, err - } - defer file.Close() - - return parseBuddyInfo(file) -} - -func parseBuddyInfo(r io.Reader) ([]BuddyInfo, error) { - var ( - buddyInfo = []BuddyInfo{} - scanner = bufio.NewScanner(r) - bucketCount = -1 - ) - - for scanner.Scan() { - var err error - line := scanner.Text() - parts := strings.Fields(line) - - if len(parts) < 4 { - return nil, fmt.Errorf("invalid number of fields when parsing buddyinfo") - } - - node := strings.TrimRight(parts[1], ",") - zone := strings.TrimRight(parts[3], ",") - arraySize := len(parts[4:]) - - if bucketCount == -1 { - bucketCount = arraySize - } else { - if bucketCount != arraySize { - return nil, fmt.Errorf("mismatch in number of buddyinfo buckets, previous count %d, new count %d", bucketCount, arraySize) - } - } - - sizes := make([]float64, arraySize) - for i := 0; i < arraySize; i++ { - sizes[i], err = strconv.ParseFloat(parts[i+4], 64) - if err != nil { - return nil, fmt.Errorf("invalid value in buddyinfo: %s", err) - } - } - - buddyInfo = append(buddyInfo, BuddyInfo{node, zone, sizes}) - } - - return buddyInfo, scanner.Err() -} diff --git a/vendor/github.com/prometheus/procfs/doc.go b/vendor/github.com/prometheus/procfs/doc.go deleted file mode 100644 index e2acd6d..0000000 --- a/vendor/github.com/prometheus/procfs/doc.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2014 Prometheus Team -// 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. - -// Package procfs provides functions to retrieve system, kernel and process -// metrics from the pseudo-filesystem proc. -// -// Example: -// -// package main -// -// import ( -// "fmt" -// "log" -// -// "github.com/prometheus/procfs" -// ) -// -// func main() { -// p, err := procfs.Self() -// if err != nil { -// log.Fatalf("could not get process: %s", err) -// } -// -// stat, err := p.NewStat() -// if err != nil { -// log.Fatalf("could not get process stat: %s", err) -// } -// -// fmt.Printf("command: %s\n", stat.Comm) -// fmt.Printf("cpu time: %fs\n", stat.CPUTime()) -// fmt.Printf("vsize: %dB\n", stat.VirtualMemory()) -// fmt.Printf("rss: %dB\n", stat.ResidentMemory()) -// } -// -package procfs diff --git a/vendor/github.com/prometheus/procfs/fixtures/26231/exe b/vendor/github.com/prometheus/procfs/fixtures/26231/exe deleted file mode 120000 index a91bec4..0000000 --- a/vendor/github.com/prometheus/procfs/fixtures/26231/exe +++ /dev/null @@ -1 +0,0 @@ -/usr/bin/vim \ No newline at end of file diff --git a/vendor/github.com/prometheus/procfs/fixtures/26231/fd/0 b/vendor/github.com/prometheus/procfs/fixtures/26231/fd/0 deleted file mode 120000 index da9c5df..0000000 --- a/vendor/github.com/prometheus/procfs/fixtures/26231/fd/0 +++ /dev/null @@ -1 +0,0 @@ -../../symlinktargets/abc \ No newline at end of file diff --git a/vendor/github.com/prometheus/procfs/fixtures/26231/fd/1 b/vendor/github.com/prometheus/procfs/fixtures/26231/fd/1 deleted file mode 120000 index ca47b50..0000000 --- a/vendor/github.com/prometheus/procfs/fixtures/26231/fd/1 +++ /dev/null @@ -1 +0,0 @@ -../../symlinktargets/def \ No newline at end of file diff --git a/vendor/github.com/prometheus/procfs/fixtures/26231/fd/10 b/vendor/github.com/prometheus/procfs/fixtures/26231/fd/10 deleted file mode 120000 index c086831..0000000 --- a/vendor/github.com/prometheus/procfs/fixtures/26231/fd/10 +++ /dev/null @@ -1 +0,0 @@ -../../symlinktargets/xyz \ No newline at end of file diff --git a/vendor/github.com/prometheus/procfs/fixtures/26231/fd/2 b/vendor/github.com/prometheus/procfs/fixtures/26231/fd/2 deleted file mode 120000 index 66731c0..0000000 --- a/vendor/github.com/prometheus/procfs/fixtures/26231/fd/2 +++ /dev/null @@ -1 +0,0 @@ -../../symlinktargets/ghi \ No newline at end of file diff --git a/vendor/github.com/prometheus/procfs/fixtures/26231/fd/3 b/vendor/github.com/prometheus/procfs/fixtures/26231/fd/3 deleted file mode 120000 index 0135dce..0000000 --- a/vendor/github.com/prometheus/procfs/fixtures/26231/fd/3 +++ /dev/null @@ -1 +0,0 @@ -../../symlinktargets/uvw \ No newline at end of file diff --git a/vendor/github.com/prometheus/procfs/fixtures/26231/ns/mnt b/vendor/github.com/prometheus/procfs/fixtures/26231/ns/mnt deleted file mode 120000 index 9c52ca2..0000000 --- a/vendor/github.com/prometheus/procfs/fixtures/26231/ns/mnt +++ /dev/null @@ -1 +0,0 @@ -mnt:[4026531840] \ No newline at end of file diff --git a/vendor/github.com/prometheus/procfs/fixtures/26231/ns/net b/vendor/github.com/prometheus/procfs/fixtures/26231/ns/net deleted file mode 120000 index 1f0f795..0000000 --- a/vendor/github.com/prometheus/procfs/fixtures/26231/ns/net +++ /dev/null @@ -1 +0,0 @@ -net:[4026531993] \ No newline at end of file diff --git a/vendor/github.com/prometheus/procfs/fixtures/26232/fd/0 b/vendor/github.com/prometheus/procfs/fixtures/26232/fd/0 deleted file mode 120000 index da9c5df..0000000 --- a/vendor/github.com/prometheus/procfs/fixtures/26232/fd/0 +++ /dev/null @@ -1 +0,0 @@ -../../symlinktargets/abc \ No newline at end of file diff --git a/vendor/github.com/prometheus/procfs/fixtures/26232/fd/1 b/vendor/github.com/prometheus/procfs/fixtures/26232/fd/1 deleted file mode 120000 index ca47b50..0000000 --- a/vendor/github.com/prometheus/procfs/fixtures/26232/fd/1 +++ /dev/null @@ -1 +0,0 @@ -../../symlinktargets/def \ No newline at end of file diff --git a/vendor/github.com/prometheus/procfs/fixtures/26232/fd/2 b/vendor/github.com/prometheus/procfs/fixtures/26232/fd/2 deleted file mode 120000 index 66731c0..0000000 --- a/vendor/github.com/prometheus/procfs/fixtures/26232/fd/2 +++ /dev/null @@ -1 +0,0 @@ -../../symlinktargets/ghi \ No newline at end of file diff --git a/vendor/github.com/prometheus/procfs/fixtures/26232/fd/3 b/vendor/github.com/prometheus/procfs/fixtures/26232/fd/3 deleted file mode 120000 index 0135dce..0000000 --- a/vendor/github.com/prometheus/procfs/fixtures/26232/fd/3 +++ /dev/null @@ -1 +0,0 @@ -../../symlinktargets/uvw \ No newline at end of file diff --git a/vendor/github.com/prometheus/procfs/fixtures/26232/fd/4 b/vendor/github.com/prometheus/procfs/fixtures/26232/fd/4 deleted file mode 120000 index c086831..0000000 --- a/vendor/github.com/prometheus/procfs/fixtures/26232/fd/4 +++ /dev/null @@ -1 +0,0 @@ -../../symlinktargets/xyz \ No newline at end of file diff --git a/vendor/github.com/prometheus/procfs/fixtures/self b/vendor/github.com/prometheus/procfs/fixtures/self deleted file mode 120000 index 1eeedea..0000000 --- a/vendor/github.com/prometheus/procfs/fixtures/self +++ /dev/null @@ -1 +0,0 @@ -26231 \ No newline at end of file diff --git a/vendor/github.com/prometheus/procfs/fs.go b/vendor/github.com/prometheus/procfs/fs.go deleted file mode 100644 index 36c1586..0000000 --- a/vendor/github.com/prometheus/procfs/fs.go +++ /dev/null @@ -1,69 +0,0 @@ -package procfs - -import ( - "fmt" - "os" - "path" - - "github.com/prometheus/procfs/nfs" - "github.com/prometheus/procfs/xfs" -) - -// FS represents the pseudo-filesystem proc, which provides an interface to -// kernel data structures. -type FS string - -// DefaultMountPoint is the common mount point of the proc filesystem. -const DefaultMountPoint = "/proc" - -// NewFS returns a new FS mounted under the given mountPoint. It will error -// if the mount point can't be read. -func NewFS(mountPoint string) (FS, error) { - info, err := os.Stat(mountPoint) - if err != nil { - return "", fmt.Errorf("could not read %s: %s", mountPoint, err) - } - if !info.IsDir() { - return "", fmt.Errorf("mount point %s is not a directory", mountPoint) - } - - return FS(mountPoint), nil -} - -// Path returns the path of the given subsystem relative to the procfs root. -func (fs FS) Path(p ...string) string { - return path.Join(append([]string{string(fs)}, p...)...) -} - -// XFSStats retrieves XFS filesystem runtime statistics. -func (fs FS) XFSStats() (*xfs.Stats, error) { - f, err := os.Open(fs.Path("fs/xfs/stat")) - if err != nil { - return nil, err - } - defer f.Close() - - return xfs.ParseStats(f) -} - -// NFSdClientRPCStats retrieves NFS daemon RPC statistics. -func (fs FS) NFSdClientRPCStats() (*nfs.ClientRPCStats, error) { - f, err := os.Open(fs.Path("net/rpc/nfs")) - if err != nil { - return nil, err - } - defer f.Close() - - return nfs.ParseClientRPCStats(f) -} - -// NFSdServerRPCStats retrieves NFS daemon RPC statistics. -func (fs FS) NFSdServerRPCStats() (*nfs.ServerRPCStats, error) { - f, err := os.Open(fs.Path("net/rpc/nfsd")) - if err != nil { - return nil, err - } - defer f.Close() - - return nfs.ParseServerRPCStats(f) -} diff --git a/vendor/github.com/prometheus/procfs/internal/util/parse.go b/vendor/github.com/prometheus/procfs/internal/util/parse.go deleted file mode 100644 index 1ad21c9..0000000 --- a/vendor/github.com/prometheus/procfs/internal/util/parse.go +++ /dev/null @@ -1,46 +0,0 @@ -// 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. - -package util - -import "strconv" - -// ParseUint32s parses a slice of strings into a slice of uint32s. -func ParseUint32s(ss []string) ([]uint32, error) { - us := make([]uint32, 0, len(ss)) - for _, s := range ss { - u, err := strconv.ParseUint(s, 10, 32) - if err != nil { - return nil, err - } - - us = append(us, uint32(u)) - } - - return us, nil -} - -// ParseUint64s parses a slice of strings into a slice of uint64s. -func ParseUint64s(ss []string) ([]uint64, error) { - us := make([]uint64, 0, len(ss)) - for _, s := range ss { - u, err := strconv.ParseUint(s, 10, 64) - if err != nil { - return nil, err - } - - us = append(us, u) - } - - return us, nil -} diff --git a/vendor/github.com/prometheus/procfs/ipvs.go b/vendor/github.com/prometheus/procfs/ipvs.go deleted file mode 100644 index 5761b45..0000000 --- a/vendor/github.com/prometheus/procfs/ipvs.go +++ /dev/null @@ -1,246 +0,0 @@ -package procfs - -import ( - "bufio" - "encoding/hex" - "errors" - "fmt" - "io" - "io/ioutil" - "net" - "os" - "strconv" - "strings" -) - -// IPVSStats holds IPVS statistics, as exposed by the kernel in `/proc/net/ip_vs_stats`. -type IPVSStats struct { - // Total count of connections. - Connections uint64 - // Total incoming packages processed. - IncomingPackets uint64 - // Total outgoing packages processed. - OutgoingPackets uint64 - // Total incoming traffic. - IncomingBytes uint64 - // Total outgoing traffic. - OutgoingBytes uint64 -} - -// IPVSBackendStatus holds current metrics of one virtual / real address pair. -type IPVSBackendStatus struct { - // The local (virtual) IP address. - LocalAddress net.IP - // The remote (real) IP address. - RemoteAddress net.IP - // The local (virtual) port. - LocalPort uint16 - // The remote (real) port. - RemotePort uint16 - // The local firewall mark - LocalMark string - // The transport protocol (TCP, UDP). - Proto string - // The current number of active connections for this virtual/real address pair. - ActiveConn uint64 - // The current number of inactive connections for this virtual/real address pair. - InactConn uint64 - // The current weight of this virtual/real address pair. - Weight uint64 -} - -// NewIPVSStats reads the IPVS statistics. -func NewIPVSStats() (IPVSStats, error) { - fs, err := NewFS(DefaultMountPoint) - if err != nil { - return IPVSStats{}, err - } - - return fs.NewIPVSStats() -} - -// NewIPVSStats reads the IPVS statistics from the specified `proc` filesystem. -func (fs FS) NewIPVSStats() (IPVSStats, error) { - file, err := os.Open(fs.Path("net/ip_vs_stats")) - if err != nil { - return IPVSStats{}, err - } - defer file.Close() - - return parseIPVSStats(file) -} - -// parseIPVSStats performs the actual parsing of `ip_vs_stats`. -func parseIPVSStats(file io.Reader) (IPVSStats, error) { - var ( - statContent []byte - statLines []string - statFields []string - stats IPVSStats - ) - - statContent, err := ioutil.ReadAll(file) - if err != nil { - return IPVSStats{}, err - } - - statLines = strings.SplitN(string(statContent), "\n", 4) - if len(statLines) != 4 { - return IPVSStats{}, errors.New("ip_vs_stats corrupt: too short") - } - - statFields = strings.Fields(statLines[2]) - if len(statFields) != 5 { - return IPVSStats{}, errors.New("ip_vs_stats corrupt: unexpected number of fields") - } - - stats.Connections, err = strconv.ParseUint(statFields[0], 16, 64) - if err != nil { - return IPVSStats{}, err - } - stats.IncomingPackets, err = strconv.ParseUint(statFields[1], 16, 64) - if err != nil { - return IPVSStats{}, err - } - stats.OutgoingPackets, err = strconv.ParseUint(statFields[2], 16, 64) - if err != nil { - return IPVSStats{}, err - } - stats.IncomingBytes, err = strconv.ParseUint(statFields[3], 16, 64) - if err != nil { - return IPVSStats{}, err - } - stats.OutgoingBytes, err = strconv.ParseUint(statFields[4], 16, 64) - if err != nil { - return IPVSStats{}, err - } - - return stats, nil -} - -// NewIPVSBackendStatus reads and returns the status of all (virtual,real) server pairs. -func NewIPVSBackendStatus() ([]IPVSBackendStatus, error) { - fs, err := NewFS(DefaultMountPoint) - if err != nil { - return []IPVSBackendStatus{}, err - } - - return fs.NewIPVSBackendStatus() -} - -// NewIPVSBackendStatus reads and returns the status of all (virtual,real) server pairs from the specified `proc` filesystem. -func (fs FS) NewIPVSBackendStatus() ([]IPVSBackendStatus, error) { - file, err := os.Open(fs.Path("net/ip_vs")) - if err != nil { - return nil, err - } - defer file.Close() - - return parseIPVSBackendStatus(file) -} - -func parseIPVSBackendStatus(file io.Reader) ([]IPVSBackendStatus, error) { - var ( - status []IPVSBackendStatus - scanner = bufio.NewScanner(file) - proto string - localMark string - localAddress net.IP - localPort uint16 - err error - ) - - for scanner.Scan() { - fields := strings.Fields(scanner.Text()) - if len(fields) == 0 { - continue - } - switch { - case fields[0] == "IP" || fields[0] == "Prot" || fields[1] == "RemoteAddress:Port": - continue - case fields[0] == "TCP" || fields[0] == "UDP": - if len(fields) < 2 { - continue - } - proto = fields[0] - localMark = "" - localAddress, localPort, err = parseIPPort(fields[1]) - if err != nil { - return nil, err - } - case fields[0] == "FWM": - if len(fields) < 2 { - continue - } - proto = fields[0] - localMark = fields[1] - localAddress = nil - localPort = 0 - case fields[0] == "->": - if len(fields) < 6 { - continue - } - remoteAddress, remotePort, err := parseIPPort(fields[1]) - if err != nil { - return nil, err - } - weight, err := strconv.ParseUint(fields[3], 10, 64) - if err != nil { - return nil, err - } - activeConn, err := strconv.ParseUint(fields[4], 10, 64) - if err != nil { - return nil, err - } - inactConn, err := strconv.ParseUint(fields[5], 10, 64) - if err != nil { - return nil, err - } - status = append(status, IPVSBackendStatus{ - LocalAddress: localAddress, - LocalPort: localPort, - LocalMark: localMark, - RemoteAddress: remoteAddress, - RemotePort: remotePort, - Proto: proto, - Weight: weight, - ActiveConn: activeConn, - InactConn: inactConn, - }) - } - } - return status, nil -} - -func parseIPPort(s string) (net.IP, uint16, error) { - var ( - ip net.IP - err error - ) - - switch len(s) { - case 13: - ip, err = hex.DecodeString(s[0:8]) - if err != nil { - return nil, 0, err - } - case 46: - ip = net.ParseIP(s[1:40]) - if ip == nil { - return nil, 0, fmt.Errorf("invalid IPv6 address: %s", s[1:40]) - } - default: - return nil, 0, fmt.Errorf("unexpected IP:Port: %s", s) - } - - portString := s[len(s)-4:] - if len(portString) != 4 { - return nil, 0, fmt.Errorf("unexpected port string format: %s", portString) - } - port, err := strconv.ParseUint(portString, 16, 16) - if err != nil { - return nil, 0, err - } - - return ip, uint16(port), nil -} diff --git a/vendor/github.com/prometheus/procfs/mdstat.go b/vendor/github.com/prometheus/procfs/mdstat.go deleted file mode 100644 index d7a248c..0000000 --- a/vendor/github.com/prometheus/procfs/mdstat.go +++ /dev/null @@ -1,138 +0,0 @@ -package procfs - -import ( - "fmt" - "io/ioutil" - "regexp" - "strconv" - "strings" -) - -var ( - statuslineRE = regexp.MustCompile(`(\d+) blocks .*\[(\d+)/(\d+)\] \[[U_]+\]`) - buildlineRE = regexp.MustCompile(`\((\d+)/\d+\)`) -) - -// MDStat holds info parsed from /proc/mdstat. -type MDStat struct { - // Name of the device. - Name string - // activity-state of the device. - ActivityState string - // Number of active disks. - DisksActive int64 - // Total number of disks the device consists of. - DisksTotal int64 - // Number of blocks the device holds. - BlocksTotal int64 - // Number of blocks on the device that are in sync. - BlocksSynced int64 -} - -// ParseMDStat parses an mdstat-file and returns a struct with the relevant infos. -func (fs FS) ParseMDStat() (mdstates []MDStat, err error) { - mdStatusFilePath := fs.Path("mdstat") - content, err := ioutil.ReadFile(mdStatusFilePath) - if err != nil { - return []MDStat{}, fmt.Errorf("error parsing %s: %s", mdStatusFilePath, err) - } - - mdStates := []MDStat{} - lines := strings.Split(string(content), "\n") - for i, l := range lines { - if l == "" { - continue - } - if l[0] == ' ' { - continue - } - if strings.HasPrefix(l, "Personalities") || strings.HasPrefix(l, "unused") { - continue - } - - mainLine := strings.Split(l, " ") - if len(mainLine) < 3 { - return mdStates, fmt.Errorf("error parsing mdline: %s", l) - } - mdName := mainLine[0] - activityState := mainLine[2] - - if len(lines) <= i+3 { - return mdStates, fmt.Errorf( - "error parsing %s: too few lines for md device %s", - mdStatusFilePath, - mdName, - ) - } - - active, total, size, err := evalStatusline(lines[i+1]) - if err != nil { - return mdStates, fmt.Errorf("error parsing %s: %s", mdStatusFilePath, err) - } - - // j is the line number of the syncing-line. - j := i + 2 - if strings.Contains(lines[i+2], "bitmap") { // skip bitmap line - j = i + 3 - } - - // If device is syncing at the moment, get the number of currently - // synced bytes, otherwise that number equals the size of the device. - syncedBlocks := size - if strings.Contains(lines[j], "recovery") || strings.Contains(lines[j], "resync") { - syncedBlocks, err = evalBuildline(lines[j]) - if err != nil { - return mdStates, fmt.Errorf("error parsing %s: %s", mdStatusFilePath, err) - } - } - - mdStates = append(mdStates, MDStat{ - Name: mdName, - ActivityState: activityState, - DisksActive: active, - DisksTotal: total, - BlocksTotal: size, - BlocksSynced: syncedBlocks, - }) - } - - return mdStates, nil -} - -func evalStatusline(statusline string) (active, total, size int64, err error) { - matches := statuslineRE.FindStringSubmatch(statusline) - if len(matches) != 4 { - return 0, 0, 0, fmt.Errorf("unexpected statusline: %s", statusline) - } - - size, err = strconv.ParseInt(matches[1], 10, 64) - if err != nil { - return 0, 0, 0, fmt.Errorf("unexpected statusline %s: %s", statusline, err) - } - - total, err = strconv.ParseInt(matches[2], 10, 64) - if err != nil { - return 0, 0, 0, fmt.Errorf("unexpected statusline %s: %s", statusline, err) - } - - active, err = strconv.ParseInt(matches[3], 10, 64) - if err != nil { - return 0, 0, 0, fmt.Errorf("unexpected statusline %s: %s", statusline, err) - } - - return active, total, size, nil -} - -func evalBuildline(buildline string) (syncedBlocks int64, err error) { - matches := buildlineRE.FindStringSubmatch(buildline) - if len(matches) != 2 { - return 0, fmt.Errorf("unexpected buildline: %s", buildline) - } - - syncedBlocks, err = strconv.ParseInt(matches[1], 10, 64) - if err != nil { - return 0, fmt.Errorf("%s in buildline: %s", err, buildline) - } - - return syncedBlocks, nil -} diff --git a/vendor/github.com/prometheus/procfs/mountstats.go b/vendor/github.com/prometheus/procfs/mountstats.go deleted file mode 100644 index 6b2b0ba..0000000 --- a/vendor/github.com/prometheus/procfs/mountstats.go +++ /dev/null @@ -1,556 +0,0 @@ -package procfs - -// While implementing parsing of /proc/[pid]/mountstats, this blog was used -// heavily as a reference: -// https://utcc.utoronto.ca/~cks/space/blog/linux/NFSMountstatsIndex -// -// Special thanks to Chris Siebenmann for all of his posts explaining the -// various statistics available for NFS. - -import ( - "bufio" - "fmt" - "io" - "strconv" - "strings" - "time" -) - -// Constants shared between multiple functions. -const ( - deviceEntryLen = 8 - - fieldBytesLen = 8 - fieldEventsLen = 27 - - statVersion10 = "1.0" - statVersion11 = "1.1" - - fieldTransport10Len = 10 - fieldTransport11Len = 13 -) - -// A Mount is a device mount parsed from /proc/[pid]/mountstats. -type Mount struct { - // Name of the device. - Device string - // The mount point of the device. - Mount string - // The filesystem type used by the device. - Type string - // If available additional statistics related to this Mount. - // Use a type assertion to determine if additional statistics are available. - Stats MountStats -} - -// A MountStats is a type which contains detailed statistics for a specific -// type of Mount. -type MountStats interface { - mountStats() -} - -// A MountStatsNFS is a MountStats implementation for NFSv3 and v4 mounts. -type MountStatsNFS struct { - // The version of statistics provided. - StatVersion string - // The age of the NFS mount. - Age time.Duration - // Statistics related to byte counters for various operations. - Bytes NFSBytesStats - // Statistics related to various NFS event occurrences. - Events NFSEventsStats - // Statistics broken down by filesystem operation. - Operations []NFSOperationStats - // Statistics about the NFS RPC transport. - Transport NFSTransportStats -} - -// mountStats implements MountStats. -func (m MountStatsNFS) mountStats() {} - -// A NFSBytesStats contains statistics about the number of bytes read and written -// by an NFS client to and from an NFS server. -type NFSBytesStats struct { - // Number of bytes read using the read() syscall. - Read uint64 - // Number of bytes written using the write() syscall. - Write uint64 - // Number of bytes read using the read() syscall in O_DIRECT mode. - DirectRead uint64 - // Number of bytes written using the write() syscall in O_DIRECT mode. - DirectWrite uint64 - // Number of bytes read from the NFS server, in total. - ReadTotal uint64 - // Number of bytes written to the NFS server, in total. - WriteTotal uint64 - // Number of pages read directly via mmap()'d files. - ReadPages uint64 - // Number of pages written directly via mmap()'d files. - WritePages uint64 -} - -// A NFSEventsStats contains statistics about NFS event occurrences. -type NFSEventsStats struct { - // Number of times cached inode attributes are re-validated from the server. - InodeRevalidate uint64 - // Number of times cached dentry nodes are re-validated from the server. - DnodeRevalidate uint64 - // Number of times an inode cache is cleared. - DataInvalidate uint64 - // Number of times cached inode attributes are invalidated. - AttributeInvalidate uint64 - // Number of times files or directories have been open()'d. - VFSOpen uint64 - // Number of times a directory lookup has occurred. - VFSLookup uint64 - // Number of times permissions have been checked. - VFSAccess uint64 - // Number of updates (and potential writes) to pages. - VFSUpdatePage uint64 - // Number of pages read directly via mmap()'d files. - VFSReadPage uint64 - // Number of times a group of pages have been read. - VFSReadPages uint64 - // Number of pages written directly via mmap()'d files. - VFSWritePage uint64 - // Number of times a group of pages have been written. - VFSWritePages uint64 - // Number of times directory entries have been read with getdents(). - VFSGetdents uint64 - // Number of times attributes have been set on inodes. - VFSSetattr uint64 - // Number of pending writes that have been forcefully flushed to the server. - VFSFlush uint64 - // Number of times fsync() has been called on directories and files. - VFSFsync uint64 - // Number of times locking has been attempted on a file. - VFSLock uint64 - // Number of times files have been closed and released. - VFSFileRelease uint64 - // Unknown. Possibly unused. - CongestionWait uint64 - // Number of times files have been truncated. - Truncation uint64 - // Number of times a file has been grown due to writes beyond its existing end. - WriteExtension uint64 - // Number of times a file was removed while still open by another process. - SillyRename uint64 - // Number of times the NFS server gave less data than expected while reading. - ShortRead uint64 - // Number of times the NFS server wrote less data than expected while writing. - ShortWrite uint64 - // Number of times the NFS server indicated EJUKEBOX; retrieving data from - // offline storage. - JukeboxDelay uint64 - // Number of NFS v4.1+ pNFS reads. - PNFSRead uint64 - // Number of NFS v4.1+ pNFS writes. - PNFSWrite uint64 -} - -// A NFSOperationStats contains statistics for a single operation. -type NFSOperationStats struct { - // The name of the operation. - Operation string - // Number of requests performed for this operation. - Requests uint64 - // Number of times an actual RPC request has been transmitted for this operation. - Transmissions uint64 - // Number of times a request has had a major timeout. - MajorTimeouts uint64 - // Number of bytes sent for this operation, including RPC headers and payload. - BytesSent uint64 - // Number of bytes received for this operation, including RPC headers and payload. - BytesReceived uint64 - // Duration all requests spent queued for transmission before they were sent. - CumulativeQueueTime time.Duration - // Duration it took to get a reply back after the request was transmitted. - CumulativeTotalResponseTime time.Duration - // Duration from when a request was enqueued to when it was completely handled. - CumulativeTotalRequestTime time.Duration -} - -// A NFSTransportStats contains statistics for the NFS mount RPC requests and -// responses. -type NFSTransportStats struct { - // The local port used for the NFS mount. - Port uint64 - // Number of times the client has had to establish a connection from scratch - // to the NFS server. - Bind uint64 - // Number of times the client has made a TCP connection to the NFS server. - Connect uint64 - // Duration (in jiffies, a kernel internal unit of time) the NFS mount has - // spent waiting for connections to the server to be established. - ConnectIdleTime uint64 - // Duration since the NFS mount last saw any RPC traffic. - IdleTime time.Duration - // Number of RPC requests for this mount sent to the NFS server. - Sends uint64 - // Number of RPC responses for this mount received from the NFS server. - Receives uint64 - // Number of times the NFS server sent a response with a transaction ID - // unknown to this client. - BadTransactionIDs uint64 - // A running counter, incremented on each request as the current difference - // ebetween sends and receives. - CumulativeActiveRequests uint64 - // A running counter, incremented on each request by the current backlog - // queue size. - CumulativeBacklog uint64 - - // Stats below only available with stat version 1.1. - - // Maximum number of simultaneously active RPC requests ever used. - MaximumRPCSlotsUsed uint64 - // A running counter, incremented on each request as the current size of the - // sending queue. - CumulativeSendingQueue uint64 - // A running counter, incremented on each request as the current size of the - // pending queue. - CumulativePendingQueue uint64 -} - -// parseMountStats parses a /proc/[pid]/mountstats file and returns a slice -// of Mount structures containing detailed information about each mount. -// If available, statistics for each mount are parsed as well. -func parseMountStats(r io.Reader) ([]*Mount, error) { - const ( - device = "device" - statVersionPrefix = "statvers=" - - nfs3Type = "nfs" - nfs4Type = "nfs4" - ) - - var mounts []*Mount - - s := bufio.NewScanner(r) - for s.Scan() { - // Only look for device entries in this function - ss := strings.Fields(string(s.Bytes())) - if len(ss) == 0 || ss[0] != device { - continue - } - - m, err := parseMount(ss) - if err != nil { - return nil, err - } - - // Does this mount also possess statistics information? - if len(ss) > deviceEntryLen { - // Only NFSv3 and v4 are supported for parsing statistics - if m.Type != nfs3Type && m.Type != nfs4Type { - return nil, fmt.Errorf("cannot parse MountStats for fstype %q", m.Type) - } - - statVersion := strings.TrimPrefix(ss[8], statVersionPrefix) - - stats, err := parseMountStatsNFS(s, statVersion) - if err != nil { - return nil, err - } - - m.Stats = stats - } - - mounts = append(mounts, m) - } - - return mounts, s.Err() -} - -// parseMount parses an entry in /proc/[pid]/mountstats in the format: -// device [device] mounted on [mount] with fstype [type] -func parseMount(ss []string) (*Mount, error) { - if len(ss) < deviceEntryLen { - return nil, fmt.Errorf("invalid device entry: %v", ss) - } - - // Check for specific words appearing at specific indices to ensure - // the format is consistent with what we expect - format := []struct { - i int - s string - }{ - {i: 0, s: "device"}, - {i: 2, s: "mounted"}, - {i: 3, s: "on"}, - {i: 5, s: "with"}, - {i: 6, s: "fstype"}, - } - - for _, f := range format { - if ss[f.i] != f.s { - return nil, fmt.Errorf("invalid device entry: %v", ss) - } - } - - return &Mount{ - Device: ss[1], - Mount: ss[4], - Type: ss[7], - }, nil -} - -// parseMountStatsNFS parses a MountStatsNFS by scanning additional information -// related to NFS statistics. -func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, error) { - // Field indicators for parsing specific types of data - const ( - fieldAge = "age:" - fieldBytes = "bytes:" - fieldEvents = "events:" - fieldPerOpStats = "per-op" - fieldTransport = "xprt:" - ) - - stats := &MountStatsNFS{ - StatVersion: statVersion, - } - - for s.Scan() { - ss := strings.Fields(string(s.Bytes())) - if len(ss) == 0 { - break - } - if len(ss) < 2 { - return nil, fmt.Errorf("not enough information for NFS stats: %v", ss) - } - - switch ss[0] { - case fieldAge: - // Age integer is in seconds - d, err := time.ParseDuration(ss[1] + "s") - if err != nil { - return nil, err - } - - stats.Age = d - case fieldBytes: - bstats, err := parseNFSBytesStats(ss[1:]) - if err != nil { - return nil, err - } - - stats.Bytes = *bstats - case fieldEvents: - estats, err := parseNFSEventsStats(ss[1:]) - if err != nil { - return nil, err - } - - stats.Events = *estats - case fieldTransport: - if len(ss) < 3 { - return nil, fmt.Errorf("not enough information for NFS transport stats: %v", ss) - } - - tstats, err := parseNFSTransportStats(ss[2:], statVersion) - if err != nil { - return nil, err - } - - stats.Transport = *tstats - } - - // When encountering "per-operation statistics", we must break this - // loop and parse them separately to ensure we can terminate parsing - // before reaching another device entry; hence why this 'if' statement - // is not just another switch case - if ss[0] == fieldPerOpStats { - break - } - } - - if err := s.Err(); err != nil { - return nil, err - } - - // NFS per-operation stats appear last before the next device entry - perOpStats, err := parseNFSOperationStats(s) - if err != nil { - return nil, err - } - - stats.Operations = perOpStats - - return stats, nil -} - -// parseNFSBytesStats parses a NFSBytesStats line using an input set of -// integer fields. -func parseNFSBytesStats(ss []string) (*NFSBytesStats, error) { - if len(ss) != fieldBytesLen { - return nil, fmt.Errorf("invalid NFS bytes stats: %v", ss) - } - - ns := make([]uint64, 0, fieldBytesLen) - for _, s := range ss { - n, err := strconv.ParseUint(s, 10, 64) - if err != nil { - return nil, err - } - - ns = append(ns, n) - } - - return &NFSBytesStats{ - Read: ns[0], - Write: ns[1], - DirectRead: ns[2], - DirectWrite: ns[3], - ReadTotal: ns[4], - WriteTotal: ns[5], - ReadPages: ns[6], - WritePages: ns[7], - }, nil -} - -// parseNFSEventsStats parses a NFSEventsStats line using an input set of -// integer fields. -func parseNFSEventsStats(ss []string) (*NFSEventsStats, error) { - if len(ss) != fieldEventsLen { - return nil, fmt.Errorf("invalid NFS events stats: %v", ss) - } - - ns := make([]uint64, 0, fieldEventsLen) - for _, s := range ss { - n, err := strconv.ParseUint(s, 10, 64) - if err != nil { - return nil, err - } - - ns = append(ns, n) - } - - return &NFSEventsStats{ - InodeRevalidate: ns[0], - DnodeRevalidate: ns[1], - DataInvalidate: ns[2], - AttributeInvalidate: ns[3], - VFSOpen: ns[4], - VFSLookup: ns[5], - VFSAccess: ns[6], - VFSUpdatePage: ns[7], - VFSReadPage: ns[8], - VFSReadPages: ns[9], - VFSWritePage: ns[10], - VFSWritePages: ns[11], - VFSGetdents: ns[12], - VFSSetattr: ns[13], - VFSFlush: ns[14], - VFSFsync: ns[15], - VFSLock: ns[16], - VFSFileRelease: ns[17], - CongestionWait: ns[18], - Truncation: ns[19], - WriteExtension: ns[20], - SillyRename: ns[21], - ShortRead: ns[22], - ShortWrite: ns[23], - JukeboxDelay: ns[24], - PNFSRead: ns[25], - PNFSWrite: ns[26], - }, nil -} - -// parseNFSOperationStats parses a slice of NFSOperationStats by scanning -// additional information about per-operation statistics until an empty -// line is reached. -func parseNFSOperationStats(s *bufio.Scanner) ([]NFSOperationStats, error) { - const ( - // Number of expected fields in each per-operation statistics set - numFields = 9 - ) - - var ops []NFSOperationStats - - for s.Scan() { - ss := strings.Fields(string(s.Bytes())) - if len(ss) == 0 { - // Must break when reading a blank line after per-operation stats to - // enable top-level function to parse the next device entry - break - } - - if len(ss) != numFields { - return nil, fmt.Errorf("invalid NFS per-operations stats: %v", ss) - } - - // Skip string operation name for integers - ns := make([]uint64, 0, numFields-1) - for _, st := range ss[1:] { - n, err := strconv.ParseUint(st, 10, 64) - if err != nil { - return nil, err - } - - ns = append(ns, n) - } - - ops = append(ops, NFSOperationStats{ - Operation: strings.TrimSuffix(ss[0], ":"), - Requests: ns[0], - Transmissions: ns[1], - MajorTimeouts: ns[2], - BytesSent: ns[3], - BytesReceived: ns[4], - CumulativeQueueTime: time.Duration(ns[5]) * time.Millisecond, - CumulativeTotalResponseTime: time.Duration(ns[6]) * time.Millisecond, - CumulativeTotalRequestTime: time.Duration(ns[7]) * time.Millisecond, - }) - } - - return ops, s.Err() -} - -// parseNFSTransportStats parses a NFSTransportStats line using an input set of -// integer fields matched to a specific stats version. -func parseNFSTransportStats(ss []string, statVersion string) (*NFSTransportStats, error) { - switch statVersion { - case statVersion10: - if len(ss) != fieldTransport10Len { - return nil, fmt.Errorf("invalid NFS transport stats 1.0 statement: %v", ss) - } - case statVersion11: - if len(ss) != fieldTransport11Len { - return nil, fmt.Errorf("invalid NFS transport stats 1.1 statement: %v", ss) - } - default: - return nil, fmt.Errorf("unrecognized NFS transport stats version: %q", statVersion) - } - - // Allocate enough for v1.1 stats since zero value for v1.1 stats will be okay - // in a v1.0 response. - // - // Note: slice length must be set to length of v1.1 stats to avoid a panic when - // only v1.0 stats are present. - // See: https://github.com/prometheus/node_exporter/issues/571. - ns := make([]uint64, fieldTransport11Len) - for i, s := range ss { - n, err := strconv.ParseUint(s, 10, 64) - if err != nil { - return nil, err - } - - ns[i] = n - } - - return &NFSTransportStats{ - Port: ns[0], - Bind: ns[1], - Connect: ns[2], - ConnectIdleTime: ns[3], - IdleTime: time.Duration(ns[4]) * time.Second, - Sends: ns[5], - Receives: ns[6], - BadTransactionIDs: ns[7], - CumulativeActiveRequests: ns[8], - CumulativeBacklog: ns[9], - MaximumRPCSlotsUsed: ns[10], - CumulativeSendingQueue: ns[11], - CumulativePendingQueue: ns[12], - }, nil -} diff --git a/vendor/github.com/prometheus/procfs/net_dev.go b/vendor/github.com/prometheus/procfs/net_dev.go deleted file mode 100644 index f8c184e..0000000 --- a/vendor/github.com/prometheus/procfs/net_dev.go +++ /dev/null @@ -1,203 +0,0 @@ -package procfs - -import ( - "bufio" - "errors" - "os" - "sort" - "strconv" - "strings" -) - -// NetDevLine is single line parsed from /proc/net/dev or /proc/[pid]/net/dev. -type NetDevLine struct { - Name string `json:"name"` // The name of the interface. - RxBytes uint64 `json:"rx_bytes"` // Cumulative count of bytes received. - RxPackets uint64 `json:"rx_packets"` // Cumulative count of packets received. - RxErrors uint64 `json:"rx_errors"` // Cumulative count of receive errors encountered. - RxDropped uint64 `json:"rx_dropped"` // Cumulative count of packets dropped while receiving. - RxFIFO uint64 `json:"rx_fifo"` // Cumulative count of FIFO buffer errors. - RxFrame uint64 `json:"rx_frame"` // Cumulative count of packet framing errors. - RxCompressed uint64 `json:"rx_compressed"` // Cumulative count of compressed packets received by the device driver. - RxMulticast uint64 `json:"rx_multicast"` // Cumulative count of multicast frames received by the device driver. - TxBytes uint64 `json:"tx_bytes"` // Cumulative count of bytes transmitted. - TxPackets uint64 `json:"tx_packets"` // Cumulative count of packets transmitted. - TxErrors uint64 `json:"tx_errors"` // Cumulative count of transmit errors encountered. - TxDropped uint64 `json:"tx_dropped"` // Cumulative count of packets dropped while transmitting. - TxFIFO uint64 `json:"tx_fifo"` // Cumulative count of FIFO buffer errors. - TxCollisions uint64 `json:"tx_collisions"` // Cumulative count of collisions detected on the interface. - TxCarrier uint64 `json:"tx_carrier"` // Cumulative count of carrier losses detected by the device driver. - TxCompressed uint64 `json:"tx_compressed"` // Cumulative count of compressed packets transmitted by the device driver. -} - -// NetDev is parsed from /proc/net/dev or /proc/[pid]/net/dev. The map keys -// are interface names. -type NetDev map[string]NetDevLine - -// NewNetDev returns kernel/system statistics read from /proc/net/dev. -func NewNetDev() (NetDev, error) { - fs, err := NewFS(DefaultMountPoint) - if err != nil { - return nil, err - } - - return fs.NewNetDev() -} - -// NewNetDev returns kernel/system statistics read from /proc/net/dev. -func (fs FS) NewNetDev() (NetDev, error) { - return newNetDev(fs.Path("net/dev")) -} - -// NewNetDev returns kernel/system statistics read from /proc/[pid]/net/dev. -func (p Proc) NewNetDev() (NetDev, error) { - return newNetDev(p.path("net/dev")) -} - -// newNetDev creates a new NetDev from the contents of the given file. -func newNetDev(file string) (NetDev, error) { - f, err := os.Open(file) - if err != nil { - return NetDev{}, err - } - defer f.Close() - - nd := NetDev{} - s := bufio.NewScanner(f) - for n := 0; s.Scan(); n++ { - // Skip the 2 header lines. - if n < 2 { - continue - } - - line, err := nd.parseLine(s.Text()) - if err != nil { - return nd, err - } - - nd[line.Name] = *line - } - - return nd, s.Err() -} - -// parseLine parses a single line from the /proc/net/dev file. Header lines -// must be filtered prior to calling this method. -func (nd NetDev) parseLine(rawLine string) (*NetDevLine, error) { - parts := strings.SplitN(rawLine, ":", 2) - if len(parts) != 2 { - return nil, errors.New("invalid net/dev line, missing colon") - } - fields := strings.Fields(strings.TrimSpace(parts[1])) - - var err error - line := &NetDevLine{} - - // Interface Name - line.Name = strings.TrimSpace(parts[0]) - if line.Name == "" { - return nil, errors.New("invalid net/dev line, empty interface name") - } - - // RX - line.RxBytes, err = strconv.ParseUint(fields[0], 10, 64) - if err != nil { - return nil, err - } - line.RxPackets, err = strconv.ParseUint(fields[1], 10, 64) - if err != nil { - return nil, err - } - line.RxErrors, err = strconv.ParseUint(fields[2], 10, 64) - if err != nil { - return nil, err - } - line.RxDropped, err = strconv.ParseUint(fields[3], 10, 64) - if err != nil { - return nil, err - } - line.RxFIFO, err = strconv.ParseUint(fields[4], 10, 64) - if err != nil { - return nil, err - } - line.RxFrame, err = strconv.ParseUint(fields[5], 10, 64) - if err != nil { - return nil, err - } - line.RxCompressed, err = strconv.ParseUint(fields[6], 10, 64) - if err != nil { - return nil, err - } - line.RxMulticast, err = strconv.ParseUint(fields[7], 10, 64) - if err != nil { - return nil, err - } - - // TX - line.TxBytes, err = strconv.ParseUint(fields[8], 10, 64) - if err != nil { - return nil, err - } - line.TxPackets, err = strconv.ParseUint(fields[9], 10, 64) - if err != nil { - return nil, err - } - line.TxErrors, err = strconv.ParseUint(fields[10], 10, 64) - if err != nil { - return nil, err - } - line.TxDropped, err = strconv.ParseUint(fields[11], 10, 64) - if err != nil { - return nil, err - } - line.TxFIFO, err = strconv.ParseUint(fields[12], 10, 64) - if err != nil { - return nil, err - } - line.TxCollisions, err = strconv.ParseUint(fields[13], 10, 64) - if err != nil { - return nil, err - } - line.TxCarrier, err = strconv.ParseUint(fields[14], 10, 64) - if err != nil { - return nil, err - } - line.TxCompressed, err = strconv.ParseUint(fields[15], 10, 64) - if err != nil { - return nil, err - } - - return line, nil -} - -// Total aggregates the values across interfaces and returns a new NetDevLine. -// The Name field will be a sorted comma seperated list of interface names. -func (nd NetDev) Total() NetDevLine { - total := NetDevLine{} - - names := make([]string, 0, len(nd)) - for _, ifc := range nd { - names = append(names, ifc.Name) - total.RxBytes += ifc.RxBytes - total.RxPackets += ifc.RxPackets - total.RxPackets += ifc.RxPackets - total.RxErrors += ifc.RxErrors - total.RxDropped += ifc.RxDropped - total.RxFIFO += ifc.RxFIFO - total.RxFrame += ifc.RxFrame - total.RxCompressed += ifc.RxCompressed - total.RxMulticast += ifc.RxMulticast - total.TxBytes += ifc.TxBytes - total.TxPackets += ifc.TxPackets - total.TxErrors += ifc.TxErrors - total.TxDropped += ifc.TxDropped - total.TxFIFO += ifc.TxFIFO - total.TxCollisions += ifc.TxCollisions - total.TxCarrier += ifc.TxCarrier - total.TxCompressed += ifc.TxCompressed - } - sort.Strings(names) - total.Name = strings.Join(names, ", ") - - return total -} diff --git a/vendor/github.com/prometheus/procfs/nfs/nfs.go b/vendor/github.com/prometheus/procfs/nfs/nfs.go deleted file mode 100644 index e2185b7..0000000 --- a/vendor/github.com/prometheus/procfs/nfs/nfs.go +++ /dev/null @@ -1,263 +0,0 @@ -// 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. - -// Package nfsd implements parsing of /proc/net/rpc/nfsd. -// Fields are documented in https://www.svennd.be/nfsd-stats-explained-procnetrpcnfsd/ -package nfs - -// ReplyCache models the "rc" line. -type ReplyCache struct { - Hits uint64 - Misses uint64 - NoCache uint64 -} - -// FileHandles models the "fh" line. -type FileHandles struct { - Stale uint64 - TotalLookups uint64 - AnonLookups uint64 - DirNoCache uint64 - NoDirNoCache uint64 -} - -// InputOutput models the "io" line. -type InputOutput struct { - Read uint64 - Write uint64 -} - -// Threads models the "th" line. -type Threads struct { - Threads uint64 - FullCnt uint64 -} - -// ReadAheadCache models the "ra" line. -type ReadAheadCache struct { - CacheSize uint64 - CacheHistogram []uint64 - NotFound uint64 -} - -// Network models the "net" line. -type Network struct { - NetCount uint64 - UDPCount uint64 - TCPCount uint64 - TCPConnect uint64 -} - -// ClientRPC models the nfs "rpc" line. -type ClientRPC struct { - RPCCount uint64 - Retransmissions uint64 - AuthRefreshes uint64 -} - -// ServerRPC models the nfsd "rpc" line. -type ServerRPC struct { - RPCCount uint64 - BadCnt uint64 - BadFmt uint64 - BadAuth uint64 - BadcInt uint64 -} - -// V2Stats models the "proc2" line. -type V2Stats struct { - Null uint64 - GetAttr uint64 - SetAttr uint64 - Root uint64 - Lookup uint64 - ReadLink uint64 - Read uint64 - WrCache uint64 - Write uint64 - Create uint64 - Remove uint64 - Rename uint64 - Link uint64 - SymLink uint64 - MkDir uint64 - RmDir uint64 - ReadDir uint64 - FsStat uint64 -} - -// V3Stats models the "proc3" line. -type V3Stats struct { - Null uint64 - GetAttr uint64 - SetAttr uint64 - Lookup uint64 - Access uint64 - ReadLink uint64 - Read uint64 - Write uint64 - Create uint64 - MkDir uint64 - SymLink uint64 - MkNod uint64 - Remove uint64 - RmDir uint64 - Rename uint64 - Link uint64 - ReadDir uint64 - ReadDirPlus uint64 - FsStat uint64 - FsInfo uint64 - PathConf uint64 - Commit uint64 -} - -// ClientV4Stats models the nfs "proc4" line. -type ClientV4Stats struct { - Null uint64 - Read uint64 - Write uint64 - Commit uint64 - Open uint64 - OpenConfirm uint64 - OpenNoattr uint64 - OpenDowngrade uint64 - Close uint64 - Setattr uint64 - FsInfo uint64 - Renew uint64 - SetClientId uint64 - SetClientIdConfirm uint64 - Lock uint64 - Lockt uint64 - Locku uint64 - Access uint64 - Getattr uint64 - Lookup uint64 - LookupRoot uint64 - Remove uint64 - Rename uint64 - Link uint64 - Symlink uint64 - Create uint64 - Pathconf uint64 - StatFs uint64 - ReadLink uint64 - ReadDir uint64 - ServerCaps uint64 - DelegReturn uint64 - GetAcl uint64 - SetAcl uint64 - FsLocations uint64 - ReleaseLockowner uint64 - Secinfo uint64 - FsidPresent uint64 - ExchangeId uint64 - CreateSession uint64 - DestroySession uint64 - Sequence uint64 - GetLeaseTime uint64 - ReclaimComplete uint64 - LayoutGet uint64 - GetDeviceInfo uint64 - LayoutCommit uint64 - LayoutReturn uint64 - SecinfoNoName uint64 - TestStateId uint64 - FreeStateId uint64 - GetDeviceList uint64 - BindConnToSession uint64 - DestroyClientId uint64 - Seek uint64 - Allocate uint64 - DeAllocate uint64 - LayoutStats uint64 - Clone uint64 -} - -// ServerV4Stats models the nfsd "proc4" line. -type ServerV4Stats struct { - Null uint64 - Compound uint64 -} - -// V4Ops models the "proc4ops" line: NFSv4 operations -// Variable list, see: -// v4.0 https://tools.ietf.org/html/rfc3010 (38 operations) -// v4.1 https://tools.ietf.org/html/rfc5661 (58 operations) -// v4.2 https://tools.ietf.org/html/draft-ietf-nfsv4-minorversion2-41 (71 operations) -type V4Ops struct { - //Values uint64 // Variable depending on v4.x sub-version. TODO: Will this always at least include the fields in this struct? - Op0Unused uint64 - Op1Unused uint64 - Op2Future uint64 - Access uint64 - Close uint64 - Commit uint64 - Create uint64 - DelegPurge uint64 - DelegReturn uint64 - GetAttr uint64 - GetFH uint64 - Link uint64 - Lock uint64 - Lockt uint64 - Locku uint64 - Lookup uint64 - LookupRoot uint64 - Nverify uint64 - Open uint64 - OpenAttr uint64 - OpenConfirm uint64 - OpenDgrd uint64 - PutFH uint64 - PutPubFH uint64 - PutRootFH uint64 - Read uint64 - ReadDir uint64 - ReadLink uint64 - Remove uint64 - Rename uint64 - Renew uint64 - RestoreFH uint64 - SaveFH uint64 - SecInfo uint64 - SetAttr uint64 - Verify uint64 - Write uint64 - RelLockOwner uint64 -} - -// RPCStats models all stats from /proc/net/rpc/nfs. -type ClientRPCStats struct { - Network Network - ClientRPC ClientRPC - V2Stats V2Stats - V3Stats V3Stats - ClientV4Stats ClientV4Stats -} - -// ServerRPCStats models all stats from /proc/net/rpc/nfsd. -type ServerRPCStats struct { - ReplyCache ReplyCache - FileHandles FileHandles - InputOutput InputOutput - Threads Threads - ReadAheadCache ReadAheadCache - Network Network - ServerRPC ServerRPC - V2Stats V2Stats - V3Stats V3Stats - ServerV4Stats ServerV4Stats - V4Ops V4Ops -} diff --git a/vendor/github.com/prometheus/procfs/nfs/parse.go b/vendor/github.com/prometheus/procfs/nfs/parse.go deleted file mode 100644 index 3aa3256..0000000 --- a/vendor/github.com/prometheus/procfs/nfs/parse.go +++ /dev/null @@ -1,308 +0,0 @@ -// 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. - -package nfs - -import ( - "fmt" -) - -func parseReplyCache(v []uint64) (ReplyCache, error) { - if len(v) != 3 { - return ReplyCache{}, fmt.Errorf("invalid ReplyCache line %q", v) - } - - return ReplyCache{ - Hits: v[0], - Misses: v[1], - NoCache: v[2], - }, nil -} - -func parseFileHandles(v []uint64) (FileHandles, error) { - if len(v) != 5 { - return FileHandles{}, fmt.Errorf("invalid FileHandles, line %q", v) - } - - return FileHandles{ - Stale: v[0], - TotalLookups: v[1], - AnonLookups: v[2], - DirNoCache: v[3], - NoDirNoCache: v[4], - }, nil -} - -func parseInputOutput(v []uint64) (InputOutput, error) { - if len(v) != 2 { - return InputOutput{}, fmt.Errorf("invalid InputOutput line %q", v) - } - - return InputOutput{ - Read: v[0], - Write: v[1], - }, nil -} - -func parseThreads(v []uint64) (Threads, error) { - if len(v) != 2 { - return Threads{}, fmt.Errorf("invalid Threads line %q", v) - } - - return Threads{ - Threads: v[0], - FullCnt: v[1], - }, nil -} - -func parseReadAheadCache(v []uint64) (ReadAheadCache, error) { - if len(v) != 12 { - return ReadAheadCache{}, fmt.Errorf("invalid ReadAheadCache line %q", v) - } - - return ReadAheadCache{ - CacheSize: v[0], - CacheHistogram: v[1:11], - NotFound: v[11], - }, nil -} - -func parseNetwork(v []uint64) (Network, error) { - if len(v) != 4 { - return Network{}, fmt.Errorf("invalid Network line %q", v) - } - - return Network{ - NetCount: v[0], - UDPCount: v[1], - TCPCount: v[2], - TCPConnect: v[3], - }, nil -} - -func parseServerRPC(v []uint64) (ServerRPC, error) { - if len(v) != 5 { - return ServerRPC{}, fmt.Errorf("invalid RPC line %q", v) - } - - return ServerRPC{ - RPCCount: v[0], - BadCnt: v[1], - BadFmt: v[2], - BadAuth: v[3], - BadcInt: v[4], - }, nil -} - -func parseClientRPC(v []uint64) (ClientRPC, error) { - if len(v) != 3 { - return ClientRPC{}, fmt.Errorf("invalid RPC line %q", v) - } - - return ClientRPC{ - RPCCount: v[0], - Retransmissions: v[1], - AuthRefreshes: v[2], - }, nil -} - -func parseV2Stats(v []uint64) (V2Stats, error) { - values := int(v[0]) - if len(v[1:]) != values || values != 18 { - return V2Stats{}, fmt.Errorf("invalid V2Stats line %q", v) - } - - return V2Stats{ - Null: v[1], - GetAttr: v[2], - SetAttr: v[3], - Root: v[4], - Lookup: v[5], - ReadLink: v[6], - Read: v[7], - WrCache: v[8], - Write: v[9], - Create: v[10], - Remove: v[11], - Rename: v[12], - Link: v[13], - SymLink: v[14], - MkDir: v[15], - RmDir: v[16], - ReadDir: v[17], - FsStat: v[18], - }, nil -} - -func parseV3Stats(v []uint64) (V3Stats, error) { - values := int(v[0]) - if len(v[1:]) != values || values != 22 { - return V3Stats{}, fmt.Errorf("invalid V3Stats line %q", v) - } - - return V3Stats{ - Null: v[1], - GetAttr: v[2], - SetAttr: v[3], - Lookup: v[4], - Access: v[5], - ReadLink: v[6], - Read: v[7], - Write: v[8], - Create: v[9], - MkDir: v[10], - SymLink: v[11], - MkNod: v[12], - Remove: v[13], - RmDir: v[14], - Rename: v[15], - Link: v[16], - ReadDir: v[17], - ReadDirPlus: v[18], - FsStat: v[19], - FsInfo: v[20], - PathConf: v[21], - Commit: v[22], - }, nil -} - -func parseClientV4Stats(v []uint64) (ClientV4Stats, error) { - values := int(v[0]) - if len(v[1:]) != values || values < 59 { - return ClientV4Stats{}, fmt.Errorf("invalid V4Stats line %q", v) - } - - return ClientV4Stats{ - Null: v[1], - Read: v[2], - Write: v[3], - Commit: v[4], - Open: v[5], - OpenConfirm: v[6], - OpenNoattr: v[7], - OpenDowngrade: v[8], - Close: v[9], - Setattr: v[10], - FsInfo: v[11], - Renew: v[12], - SetClientId: v[13], - SetClientIdConfirm: v[14], - Lock: v[15], - Lockt: v[16], - Locku: v[17], - Access: v[18], - Getattr: v[19], - Lookup: v[20], - LookupRoot: v[21], - Remove: v[22], - Rename: v[23], - Link: v[24], - Symlink: v[25], - Create: v[26], - Pathconf: v[27], - StatFs: v[28], - ReadLink: v[29], - ReadDir: v[30], - ServerCaps: v[31], - DelegReturn: v[32], - GetAcl: v[33], - SetAcl: v[34], - FsLocations: v[35], - ReleaseLockowner: v[36], - Secinfo: v[37], - FsidPresent: v[38], - ExchangeId: v[39], - CreateSession: v[40], - DestroySession: v[41], - Sequence: v[42], - GetLeaseTime: v[43], - ReclaimComplete: v[44], - LayoutGet: v[45], - GetDeviceInfo: v[46], - LayoutCommit: v[47], - LayoutReturn: v[48], - SecinfoNoName: v[49], - TestStateId: v[50], - FreeStateId: v[51], - GetDeviceList: v[52], - BindConnToSession: v[53], - DestroyClientId: v[54], - Seek: v[55], - Allocate: v[56], - DeAllocate: v[57], - LayoutStats: v[58], - Clone: v[59], - }, nil -} - -func parseServerV4Stats(v []uint64) (ServerV4Stats, error) { - values := int(v[0]) - if len(v[1:]) != values || values != 2 { - return ServerV4Stats{}, fmt.Errorf("invalid V4Stats line %q", v) - } - - return ServerV4Stats{ - Null: v[1], - Compound: v[2], - }, nil -} - -func parseV4Ops(v []uint64) (V4Ops, error) { - values := int(v[0]) - if len(v[1:]) != values || values < 39 { - return V4Ops{}, fmt.Errorf("invalid V4Ops line %q", v) - } - - stats := V4Ops{ - Op0Unused: v[1], - Op1Unused: v[2], - Op2Future: v[3], - Access: v[4], - Close: v[5], - Commit: v[6], - Create: v[7], - DelegPurge: v[8], - DelegReturn: v[9], - GetAttr: v[10], - GetFH: v[11], - Link: v[12], - Lock: v[13], - Lockt: v[14], - Locku: v[15], - Lookup: v[16], - LookupRoot: v[17], - Nverify: v[18], - Open: v[19], - OpenAttr: v[20], - OpenConfirm: v[21], - OpenDgrd: v[22], - PutFH: v[23], - PutPubFH: v[24], - PutRootFH: v[25], - Read: v[26], - ReadDir: v[27], - ReadLink: v[28], - Remove: v[29], - Rename: v[30], - Renew: v[31], - RestoreFH: v[32], - SaveFH: v[33], - SecInfo: v[34], - SetAttr: v[35], - Verify: v[36], - Write: v[37], - RelLockOwner: v[38], - } - - return stats, nil -} diff --git a/vendor/github.com/prometheus/procfs/nfs/parse_nfs.go b/vendor/github.com/prometheus/procfs/nfs/parse_nfs.go deleted file mode 100644 index b5c0b15..0000000 --- a/vendor/github.com/prometheus/procfs/nfs/parse_nfs.go +++ /dev/null @@ -1,67 +0,0 @@ -// 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. - -package nfs - -import ( - "bufio" - "fmt" - "io" - "strings" - - "github.com/prometheus/procfs/internal/util" -) - -// ParseClientRPCStats returns stats read from /proc/net/rpc/nfs -func ParseClientRPCStats(r io.Reader) (*ClientRPCStats, error) { - stats := &ClientRPCStats{} - - scanner := bufio.NewScanner(r) - for scanner.Scan() { - line := scanner.Text() - parts := strings.Fields(scanner.Text()) - // require at least - if len(parts) < 2 { - return nil, fmt.Errorf("invalid NFSd metric line %q", line) - } - - values, err := util.ParseUint64s(parts[1:]) - if err != nil { - return nil, fmt.Errorf("error parsing NFSd metric line: %s", err) - } - - switch metricLine := parts[0]; metricLine { - case "net": - stats.Network, err = parseNetwork(values) - case "rpc": - stats.ClientRPC, err = parseClientRPC(values) - case "proc2": - stats.V2Stats, err = parseV2Stats(values) - case "proc3": - stats.V3Stats, err = parseV3Stats(values) - case "proc4": - stats.ClientV4Stats, err = parseClientV4Stats(values) - default: - return nil, fmt.Errorf("unknown NFSd metric line %q", metricLine) - } - if err != nil { - return nil, fmt.Errorf("errors parsing NFSd metric line: %s", err) - } - } - - if err := scanner.Err(); err != nil { - return nil, fmt.Errorf("error scanning NFSd file: %s", err) - } - - return stats, nil -} diff --git a/vendor/github.com/prometheus/procfs/nfs/parse_nfsd.go b/vendor/github.com/prometheus/procfs/nfs/parse_nfsd.go deleted file mode 100644 index 57bb4a3..0000000 --- a/vendor/github.com/prometheus/procfs/nfs/parse_nfsd.go +++ /dev/null @@ -1,89 +0,0 @@ -// 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. - -package nfs - -import ( - "bufio" - "fmt" - "io" - "strings" - - "github.com/prometheus/procfs/internal/util" -) - -// ParseServerRPCStats returns stats read from /proc/net/rpc/nfsd -func ParseServerRPCStats(r io.Reader) (*ServerRPCStats, error) { - stats := &ServerRPCStats{} - - scanner := bufio.NewScanner(r) - for scanner.Scan() { - line := scanner.Text() - parts := strings.Fields(scanner.Text()) - // require at least - if len(parts) < 2 { - return nil, fmt.Errorf("invalid NFSd metric line %q", line) - } - label := parts[0] - - var values []uint64 - var err error - if label == "th" { - if len(parts) < 3 { - return nil, fmt.Errorf("invalid NFSd th metric line %q", line) - } - values, err = util.ParseUint64s(parts[1:3]) - } else { - values, err = util.ParseUint64s(parts[1:]) - } - if err != nil { - return nil, fmt.Errorf("error parsing NFSd metric line: %s", err) - } - - switch metricLine := parts[0]; metricLine { - case "rc": - stats.ReplyCache, err = parseReplyCache(values) - case "fh": - stats.FileHandles, err = parseFileHandles(values) - case "io": - stats.InputOutput, err = parseInputOutput(values) - case "th": - stats.Threads, err = parseThreads(values) - case "ra": - stats.ReadAheadCache, err = parseReadAheadCache(values) - case "net": - stats.Network, err = parseNetwork(values) - case "rpc": - stats.ServerRPC, err = parseServerRPC(values) - case "proc2": - stats.V2Stats, err = parseV2Stats(values) - case "proc3": - stats.V3Stats, err = parseV3Stats(values) - case "proc4": - stats.ServerV4Stats, err = parseServerV4Stats(values) - case "proc4ops": - stats.V4Ops, err = parseV4Ops(values) - default: - return nil, fmt.Errorf("unknown NFSd metric line %q", metricLine) - } - if err != nil { - return nil, fmt.Errorf("errors parsing NFSd metric line: %s", err) - } - } - - if err := scanner.Err(); err != nil { - return nil, fmt.Errorf("error scanning NFSd file: %s", err) - } - - return stats, nil -} diff --git a/vendor/github.com/prometheus/procfs/proc.go b/vendor/github.com/prometheus/procfs/proc.go deleted file mode 100644 index 8717e1f..0000000 --- a/vendor/github.com/prometheus/procfs/proc.go +++ /dev/null @@ -1,224 +0,0 @@ -package procfs - -import ( - "fmt" - "io/ioutil" - "os" - "strconv" - "strings" -) - -// Proc provides information about a running process. -type Proc struct { - // The process ID. - PID int - - fs FS -} - -// Procs represents a list of Proc structs. -type Procs []Proc - -func (p Procs) Len() int { return len(p) } -func (p Procs) Swap(i, j int) { p[i], p[j] = p[j], p[i] } -func (p Procs) Less(i, j int) bool { return p[i].PID < p[j].PID } - -// Self returns a process for the current process read via /proc/self. -func Self() (Proc, error) { - fs, err := NewFS(DefaultMountPoint) - if err != nil { - return Proc{}, err - } - return fs.Self() -} - -// NewProc returns a process for the given pid under /proc. -func NewProc(pid int) (Proc, error) { - fs, err := NewFS(DefaultMountPoint) - if err != nil { - return Proc{}, err - } - return fs.NewProc(pid) -} - -// AllProcs returns a list of all currently available processes under /proc. -func AllProcs() (Procs, error) { - fs, err := NewFS(DefaultMountPoint) - if err != nil { - return Procs{}, err - } - return fs.AllProcs() -} - -// Self returns a process for the current process. -func (fs FS) Self() (Proc, error) { - p, err := os.Readlink(fs.Path("self")) - if err != nil { - return Proc{}, err - } - pid, err := strconv.Atoi(strings.Replace(p, string(fs), "", -1)) - if err != nil { - return Proc{}, err - } - return fs.NewProc(pid) -} - -// NewProc returns a process for the given pid. -func (fs FS) NewProc(pid int) (Proc, error) { - if _, err := os.Stat(fs.Path(strconv.Itoa(pid))); err != nil { - return Proc{}, err - } - return Proc{PID: pid, fs: fs}, nil -} - -// AllProcs returns a list of all currently available processes. -func (fs FS) AllProcs() (Procs, error) { - d, err := os.Open(fs.Path()) - if err != nil { - return Procs{}, err - } - defer d.Close() - - names, err := d.Readdirnames(-1) - if err != nil { - return Procs{}, fmt.Errorf("could not read %s: %s", d.Name(), err) - } - - p := Procs{} - for _, n := range names { - pid, err := strconv.ParseInt(n, 10, 64) - if err != nil { - continue - } - p = append(p, Proc{PID: int(pid), fs: fs}) - } - - return p, nil -} - -// CmdLine returns the command line of a process. -func (p Proc) CmdLine() ([]string, error) { - f, err := os.Open(p.path("cmdline")) - if err != nil { - return nil, err - } - defer f.Close() - - data, err := ioutil.ReadAll(f) - if err != nil { - return nil, err - } - - if len(data) < 1 { - return []string{}, nil - } - - return strings.Split(string(data[:len(data)-1]), string(byte(0))), nil -} - -// Comm returns the command name of a process. -func (p Proc) Comm() (string, error) { - f, err := os.Open(p.path("comm")) - if err != nil { - return "", err - } - defer f.Close() - - data, err := ioutil.ReadAll(f) - if err != nil { - return "", err - } - - return strings.TrimSpace(string(data)), nil -} - -// Executable returns the absolute path of the executable command of a process. -func (p Proc) Executable() (string, error) { - exe, err := os.Readlink(p.path("exe")) - if os.IsNotExist(err) { - return "", nil - } - - return exe, err -} - -// FileDescriptors returns the currently open file descriptors of a process. -func (p Proc) FileDescriptors() ([]uintptr, error) { - names, err := p.fileDescriptors() - if err != nil { - return nil, err - } - - fds := make([]uintptr, len(names)) - for i, n := range names { - fd, err := strconv.ParseInt(n, 10, 32) - if err != nil { - return nil, fmt.Errorf("could not parse fd %s: %s", n, err) - } - fds[i] = uintptr(fd) - } - - return fds, nil -} - -// FileDescriptorTargets returns the targets of all file descriptors of a process. -// If a file descriptor is not a symlink to a file (like a socket), that value will be the empty string. -func (p Proc) FileDescriptorTargets() ([]string, error) { - names, err := p.fileDescriptors() - if err != nil { - return nil, err - } - - targets := make([]string, len(names)) - - for i, name := range names { - target, err := os.Readlink(p.path("fd", name)) - if err == nil { - targets[i] = target - } - } - - return targets, nil -} - -// FileDescriptorsLen returns the number of currently open file descriptors of -// a process. -func (p Proc) FileDescriptorsLen() (int, error) { - fds, err := p.fileDescriptors() - if err != nil { - return 0, err - } - - return len(fds), nil -} - -// MountStats retrieves statistics and configuration for mount points in a -// process's namespace. -func (p Proc) MountStats() ([]*Mount, error) { - f, err := os.Open(p.path("mountstats")) - if err != nil { - return nil, err - } - defer f.Close() - - return parseMountStats(f) -} - -func (p Proc) fileDescriptors() ([]string, error) { - d, err := os.Open(p.path("fd")) - if err != nil { - return nil, err - } - defer d.Close() - - names, err := d.Readdirnames(-1) - if err != nil { - return nil, fmt.Errorf("could not read %s: %s", d.Name(), err) - } - - return names, nil -} - -func (p Proc) path(pa ...string) string { - return p.fs.Path(append([]string{strconv.Itoa(p.PID)}, pa...)...) -} diff --git a/vendor/github.com/prometheus/procfs/proc_io.go b/vendor/github.com/prometheus/procfs/proc_io.go deleted file mode 100644 index e7f6674..0000000 --- a/vendor/github.com/prometheus/procfs/proc_io.go +++ /dev/null @@ -1,52 +0,0 @@ -package procfs - -import ( - "fmt" - "io/ioutil" - "os" -) - -// ProcIO models the content of /proc//io. -type ProcIO struct { - // Chars read. - RChar uint64 - // Chars written. - WChar uint64 - // Read syscalls. - SyscR uint64 - // Write syscalls. - SyscW uint64 - // Bytes read. - ReadBytes uint64 - // Bytes written. - WriteBytes uint64 - // Bytes written, but taking into account truncation. See - // Documentation/filesystems/proc.txt in the kernel sources for - // detailed explanation. - CancelledWriteBytes int64 -} - -// NewIO creates a new ProcIO instance from a given Proc instance. -func (p Proc) NewIO() (ProcIO, error) { - pio := ProcIO{} - - f, err := os.Open(p.path("io")) - if err != nil { - return pio, err - } - defer f.Close() - - data, err := ioutil.ReadAll(f) - if err != nil { - return pio, err - } - - ioFormat := "rchar: %d\nwchar: %d\nsyscr: %d\nsyscw: %d\n" + - "read_bytes: %d\nwrite_bytes: %d\n" + - "cancelled_write_bytes: %d\n" - - _, err = fmt.Sscanf(string(data), ioFormat, &pio.RChar, &pio.WChar, &pio.SyscR, - &pio.SyscW, &pio.ReadBytes, &pio.WriteBytes, &pio.CancelledWriteBytes) - - return pio, err -} diff --git a/vendor/github.com/prometheus/procfs/proc_limits.go b/vendor/github.com/prometheus/procfs/proc_limits.go deleted file mode 100644 index b684a5b..0000000 --- a/vendor/github.com/prometheus/procfs/proc_limits.go +++ /dev/null @@ -1,137 +0,0 @@ -package procfs - -import ( - "bufio" - "fmt" - "os" - "regexp" - "strconv" -) - -// ProcLimits represents the soft limits for each of the process's resource -// limits. For more information see getrlimit(2): -// http://man7.org/linux/man-pages/man2/getrlimit.2.html. -type ProcLimits struct { - // CPU time limit in seconds. - CPUTime int64 - // Maximum size of files that the process may create. - FileSize int64 - // Maximum size of the process's data segment (initialized data, - // uninitialized data, and heap). - DataSize int64 - // Maximum size of the process stack in bytes. - StackSize int64 - // Maximum size of a core file. - CoreFileSize int64 - // Limit of the process's resident set in pages. - ResidentSet int64 - // Maximum number of processes that can be created for the real user ID of - // the calling process. - Processes int64 - // Value one greater than the maximum file descriptor number that can be - // opened by this process. - OpenFiles int64 - // Maximum number of bytes of memory that may be locked into RAM. - LockedMemory int64 - // Maximum size of the process's virtual memory address space in bytes. - AddressSpace int64 - // Limit on the combined number of flock(2) locks and fcntl(2) leases that - // this process may establish. - FileLocks int64 - // Limit of signals that may be queued for the real user ID of the calling - // process. - PendingSignals int64 - // Limit on the number of bytes that can be allocated for POSIX message - // queues for the real user ID of the calling process. - MsqqueueSize int64 - // Limit of the nice priority set using setpriority(2) or nice(2). - NicePriority int64 - // Limit of the real-time priority set using sched_setscheduler(2) or - // sched_setparam(2). - RealtimePriority int64 - // Limit (in microseconds) on the amount of CPU time that a process - // scheduled under a real-time scheduling policy may consume without making - // a blocking system call. - RealtimeTimeout int64 -} - -const ( - limitsFields = 3 - limitsUnlimited = "unlimited" -) - -var ( - limitsDelimiter = regexp.MustCompile(" +") -) - -// NewLimits returns the current soft limits of the process. -func (p Proc) NewLimits() (ProcLimits, error) { - f, err := os.Open(p.path("limits")) - if err != nil { - return ProcLimits{}, err - } - defer f.Close() - - var ( - l = ProcLimits{} - s = bufio.NewScanner(f) - ) - for s.Scan() { - fields := limitsDelimiter.Split(s.Text(), limitsFields) - if len(fields) != limitsFields { - return ProcLimits{}, fmt.Errorf( - "couldn't parse %s line %s", f.Name(), s.Text()) - } - - switch fields[0] { - case "Max cpu time": - l.CPUTime, err = parseInt(fields[1]) - case "Max file size": - l.FileSize, err = parseInt(fields[1]) - case "Max data size": - l.DataSize, err = parseInt(fields[1]) - case "Max stack size": - l.StackSize, err = parseInt(fields[1]) - case "Max core file size": - l.CoreFileSize, err = parseInt(fields[1]) - case "Max resident set": - l.ResidentSet, err = parseInt(fields[1]) - case "Max processes": - l.Processes, err = parseInt(fields[1]) - case "Max open files": - l.OpenFiles, err = parseInt(fields[1]) - case "Max locked memory": - l.LockedMemory, err = parseInt(fields[1]) - case "Max address space": - l.AddressSpace, err = parseInt(fields[1]) - case "Max file locks": - l.FileLocks, err = parseInt(fields[1]) - case "Max pending signals": - l.PendingSignals, err = parseInt(fields[1]) - case "Max msgqueue size": - l.MsqqueueSize, err = parseInt(fields[1]) - case "Max nice priority": - l.NicePriority, err = parseInt(fields[1]) - case "Max realtime priority": - l.RealtimePriority, err = parseInt(fields[1]) - case "Max realtime timeout": - l.RealtimeTimeout, err = parseInt(fields[1]) - } - if err != nil { - return ProcLimits{}, err - } - } - - return l, s.Err() -} - -func parseInt(s string) (int64, error) { - if s == limitsUnlimited { - return -1, nil - } - i, err := strconv.ParseInt(s, 10, 64) - if err != nil { - return 0, fmt.Errorf("couldn't parse value %s: %s", s, err) - } - return i, nil -} diff --git a/vendor/github.com/prometheus/procfs/proc_ns.go b/vendor/github.com/prometheus/procfs/proc_ns.go deleted file mode 100644 index befdd26..0000000 --- a/vendor/github.com/prometheus/procfs/proc_ns.go +++ /dev/null @@ -1,55 +0,0 @@ -package procfs - -import ( - "fmt" - "os" - "strconv" - "strings" -) - -// Namespace represents a single namespace of a process. -type Namespace struct { - Type string // Namespace type. - Inode uint32 // Inode number of the namespace. If two processes are in the same namespace their inodes will match. -} - -// Namespaces contains all of the namespaces that the process is contained in. -type Namespaces map[string]Namespace - -// NewNamespaces reads from /proc/[pid/ns/* to get the namespaces of which the -// process is a member. -func (p Proc) NewNamespaces() (Namespaces, error) { - d, err := os.Open(p.path("ns")) - if err != nil { - return nil, err - } - defer d.Close() - - names, err := d.Readdirnames(-1) - if err != nil { - return nil, fmt.Errorf("failed to read contents of ns dir: %v", err) - } - - ns := make(Namespaces, len(names)) - for _, name := range names { - target, err := os.Readlink(p.path("ns", name)) - if err != nil { - return nil, err - } - - fields := strings.SplitN(target, ":", 2) - if len(fields) != 2 { - return nil, fmt.Errorf("failed to parse namespace type and inode from '%v'", target) - } - - typ := fields[0] - inode, err := strconv.ParseUint(strings.Trim(fields[1], "[]"), 10, 32) - if err != nil { - return nil, fmt.Errorf("failed to parse inode from '%v': %v", fields[1], err) - } - - ns[name] = Namespace{typ, uint32(inode)} - } - - return ns, nil -} diff --git a/vendor/github.com/prometheus/procfs/proc_stat.go b/vendor/github.com/prometheus/procfs/proc_stat.go deleted file mode 100644 index 724e271..0000000 --- a/vendor/github.com/prometheus/procfs/proc_stat.go +++ /dev/null @@ -1,175 +0,0 @@ -package procfs - -import ( - "bytes" - "fmt" - "io/ioutil" - "os" -) - -// Originally, this USER_HZ value was dynamically retrieved via a sysconf call -// which required cgo. However, that caused a lot of problems regarding -// cross-compilation. Alternatives such as running a binary to determine the -// value, or trying to derive it in some other way were all problematic. After -// much research it was determined that USER_HZ is actually hardcoded to 100 on -// all Go-supported platforms as of the time of this writing. This is why we -// decided to hardcode it here as well. It is not impossible that there could -// be systems with exceptions, but they should be very exotic edge cases, and -// in that case, the worst outcome will be two misreported metrics. -// -// See also the following discussions: -// -// - https://github.com/prometheus/node_exporter/issues/52 -// - https://github.com/prometheus/procfs/pull/2 -// - http://stackoverflow.com/questions/17410841/how-does-user-hz-solve-the-jiffy-scaling-issue -const userHZ = 100 - -// ProcStat provides status information about the process, -// read from /proc/[pid]/stat. -type ProcStat struct { - // The process ID. - PID int - // The filename of the executable. - Comm string - // The process state. - State string - // The PID of the parent of this process. - PPID int - // The process group ID of the process. - PGRP int - // The session ID of the process. - Session int - // The controlling terminal of the process. - TTY int - // The ID of the foreground process group of the controlling terminal of - // the process. - TPGID int - // The kernel flags word of the process. - Flags uint - // The number of minor faults the process has made which have not required - // loading a memory page from disk. - MinFlt uint - // The number of minor faults that the process's waited-for children have - // made. - CMinFlt uint - // The number of major faults the process has made which have required - // loading a memory page from disk. - MajFlt uint - // The number of major faults that the process's waited-for children have - // made. - CMajFlt uint - // Amount of time that this process has been scheduled in user mode, - // measured in clock ticks. - UTime uint - // Amount of time that this process has been scheduled in kernel mode, - // measured in clock ticks. - STime uint - // Amount of time that this process's waited-for children have been - // scheduled in user mode, measured in clock ticks. - CUTime uint - // Amount of time that this process's waited-for children have been - // scheduled in kernel mode, measured in clock ticks. - CSTime uint - // For processes running a real-time scheduling policy, this is the negated - // scheduling priority, minus one. - Priority int - // The nice value, a value in the range 19 (low priority) to -20 (high - // priority). - Nice int - // Number of threads in this process. - NumThreads int - // The time the process started after system boot, the value is expressed - // in clock ticks. - Starttime uint64 - // Virtual memory size in bytes. - VSize int - // Resident set size in pages. - RSS int - - fs FS -} - -// NewStat returns the current status information of the process. -func (p Proc) NewStat() (ProcStat, error) { - f, err := os.Open(p.path("stat")) - if err != nil { - return ProcStat{}, err - } - defer f.Close() - - data, err := ioutil.ReadAll(f) - if err != nil { - return ProcStat{}, err - } - - var ( - ignore int - - s = ProcStat{PID: p.PID, fs: p.fs} - l = bytes.Index(data, []byte("(")) - r = bytes.LastIndex(data, []byte(")")) - ) - - if l < 0 || r < 0 { - return ProcStat{}, fmt.Errorf( - "unexpected format, couldn't extract comm: %s", - data, - ) - } - - s.Comm = string(data[l+1 : r]) - _, err = fmt.Fscan( - bytes.NewBuffer(data[r+2:]), - &s.State, - &s.PPID, - &s.PGRP, - &s.Session, - &s.TTY, - &s.TPGID, - &s.Flags, - &s.MinFlt, - &s.CMinFlt, - &s.MajFlt, - &s.CMajFlt, - &s.UTime, - &s.STime, - &s.CUTime, - &s.CSTime, - &s.Priority, - &s.Nice, - &s.NumThreads, - &ignore, - &s.Starttime, - &s.VSize, - &s.RSS, - ) - if err != nil { - return ProcStat{}, err - } - - return s, nil -} - -// VirtualMemory returns the virtual memory size in bytes. -func (s ProcStat) VirtualMemory() int { - return s.VSize -} - -// ResidentMemory returns the resident memory size in bytes. -func (s ProcStat) ResidentMemory() int { - return s.RSS * os.Getpagesize() -} - -// StartTime returns the unix timestamp of the process in seconds. -func (s ProcStat) StartTime() (float64, error) { - stat, err := s.fs.NewStat() - if err != nil { - return 0, err - } - return float64(stat.BootTime) + (float64(s.Starttime) / userHZ), nil -} - -// CPUTime returns the total CPU user and system time in seconds. -func (s ProcStat) CPUTime() float64 { - return float64(s.UTime+s.STime) / userHZ -} diff --git a/vendor/github.com/prometheus/procfs/stat.go b/vendor/github.com/prometheus/procfs/stat.go deleted file mode 100644 index 701f4df..0000000 --- a/vendor/github.com/prometheus/procfs/stat.go +++ /dev/null @@ -1,219 +0,0 @@ -package procfs - -import ( - "bufio" - "fmt" - "io" - "os" - "strconv" - "strings" -) - -// CPUStat shows how much time the cpu spend in various stages. -type CPUStat struct { - User float64 - Nice float64 - System float64 - Idle float64 - Iowait float64 - IRQ float64 - SoftIRQ float64 - Steal float64 - Guest float64 - GuestNice float64 -} - -// SoftIRQStat represent the softirq statistics as exported in the procfs stat file. -// A nice introduction can be found at https://0xax.gitbooks.io/linux-insides/content/interrupts/interrupts-9.html -// It is possible to get per-cpu stats by reading /proc/softirqs -type SoftIRQStat struct { - Hi uint64 - Timer uint64 - NetTx uint64 - NetRx uint64 - Block uint64 - BlockIoPoll uint64 - Tasklet uint64 - Sched uint64 - Hrtimer uint64 - Rcu uint64 -} - -// Stat represents kernel/system statistics. -type Stat struct { - // Boot time in seconds since the Epoch. - BootTime uint64 - // Summed up cpu statistics. - CPUTotal CPUStat - // Per-CPU statistics. - CPU []CPUStat - // Number of times interrupts were handled, which contains numbered and unnumbered IRQs. - IRQTotal uint64 - // Number of times a numbered IRQ was triggered. - IRQ []uint64 - // Number of times a context switch happened. - ContextSwitches uint64 - // Number of times a process was created. - ProcessCreated uint64 - // Number of processes currently running. - ProcessesRunning uint64 - // Number of processes currently blocked (waiting for IO). - ProcessesBlocked uint64 - // Number of times a softirq was scheduled. - SoftIRQTotal uint64 - // Detailed softirq statistics. - SoftIRQ SoftIRQStat -} - -// NewStat returns kernel/system statistics read from /proc/stat. -func NewStat() (Stat, error) { - fs, err := NewFS(DefaultMountPoint) - if err != nil { - return Stat{}, err - } - - return fs.NewStat() -} - -// Parse a cpu statistics line and returns the CPUStat struct plus the cpu id (or -1 for the overall sum). -func parseCPUStat(line string) (CPUStat, int64, error) { - cpuStat := CPUStat{} - var cpu string - - count, err := fmt.Sscanf(line, "%s %f %f %f %f %f %f %f %f %f %f", - &cpu, - &cpuStat.User, &cpuStat.Nice, &cpuStat.System, &cpuStat.Idle, - &cpuStat.Iowait, &cpuStat.IRQ, &cpuStat.SoftIRQ, &cpuStat.Steal, - &cpuStat.Guest, &cpuStat.GuestNice) - - if err != nil && err != io.EOF { - return CPUStat{}, -1, fmt.Errorf("couldn't parse %s (cpu): %s", line, err) - } - if count == 0 { - return CPUStat{}, -1, fmt.Errorf("couldn't parse %s (cpu): 0 elements parsed", line) - } - - cpuStat.User /= userHZ - cpuStat.Nice /= userHZ - cpuStat.System /= userHZ - cpuStat.Idle /= userHZ - cpuStat.Iowait /= userHZ - cpuStat.IRQ /= userHZ - cpuStat.SoftIRQ /= userHZ - cpuStat.Steal /= userHZ - cpuStat.Guest /= userHZ - cpuStat.GuestNice /= userHZ - - if cpu == "cpu" { - return cpuStat, -1, nil - } - - cpuID, err := strconv.ParseInt(cpu[3:], 10, 64) - if err != nil { - return CPUStat{}, -1, fmt.Errorf("couldn't parse %s (cpu/cpuid): %s", line, err) - } - - return cpuStat, cpuID, nil -} - -// Parse a softirq line. -func parseSoftIRQStat(line string) (SoftIRQStat, uint64, error) { - softIRQStat := SoftIRQStat{} - var total uint64 - var prefix string - - _, err := fmt.Sscanf(line, "%s %d %d %d %d %d %d %d %d %d %d %d", - &prefix, &total, - &softIRQStat.Hi, &softIRQStat.Timer, &softIRQStat.NetTx, &softIRQStat.NetRx, - &softIRQStat.Block, &softIRQStat.BlockIoPoll, - &softIRQStat.Tasklet, &softIRQStat.Sched, - &softIRQStat.Hrtimer, &softIRQStat.Rcu) - - if err != nil { - return SoftIRQStat{}, 0, fmt.Errorf("couldn't parse %s (softirq): %s", line, err) - } - - return softIRQStat, total, nil -} - -// NewStat returns an information about current kernel/system statistics. -func (fs FS) NewStat() (Stat, error) { - // See https://www.kernel.org/doc/Documentation/filesystems/proc.txt - - f, err := os.Open(fs.Path("stat")) - if err != nil { - return Stat{}, err - } - defer f.Close() - - stat := Stat{} - - scanner := bufio.NewScanner(f) - for scanner.Scan() { - line := scanner.Text() - parts := strings.Fields(scanner.Text()) - // require at least - if len(parts) < 2 { - continue - } - switch { - case parts[0] == "btime": - if stat.BootTime, err = strconv.ParseUint(parts[1], 10, 64); err != nil { - return Stat{}, fmt.Errorf("couldn't parse %s (btime): %s", parts[1], err) - } - case parts[0] == "intr": - if stat.IRQTotal, err = strconv.ParseUint(parts[1], 10, 64); err != nil { - return Stat{}, fmt.Errorf("couldn't parse %s (intr): %s", parts[1], err) - } - numberedIRQs := parts[2:] - stat.IRQ = make([]uint64, len(numberedIRQs)) - for i, count := range numberedIRQs { - if stat.IRQ[i], err = strconv.ParseUint(count, 10, 64); err != nil { - return Stat{}, fmt.Errorf("couldn't parse %s (intr%d): %s", count, i, err) - } - } - case parts[0] == "ctxt": - if stat.ContextSwitches, err = strconv.ParseUint(parts[1], 10, 64); err != nil { - return Stat{}, fmt.Errorf("couldn't parse %s (ctxt): %s", parts[1], err) - } - case parts[0] == "processes": - if stat.ProcessCreated, err = strconv.ParseUint(parts[1], 10, 64); err != nil { - return Stat{}, fmt.Errorf("couldn't parse %s (processes): %s", parts[1], err) - } - case parts[0] == "procs_running": - if stat.ProcessesRunning, err = strconv.ParseUint(parts[1], 10, 64); err != nil { - return Stat{}, fmt.Errorf("couldn't parse %s (procs_running): %s", parts[1], err) - } - case parts[0] == "procs_blocked": - if stat.ProcessesBlocked, err = strconv.ParseUint(parts[1], 10, 64); err != nil { - return Stat{}, fmt.Errorf("couldn't parse %s (procs_blocked): %s", parts[1], err) - } - case parts[0] == "softirq": - softIRQStats, total, err := parseSoftIRQStat(line) - if err != nil { - return Stat{}, err - } - stat.SoftIRQTotal = total - stat.SoftIRQ = softIRQStats - case strings.HasPrefix(parts[0], "cpu"): - cpuStat, cpuID, err := parseCPUStat(line) - if err != nil { - return Stat{}, err - } - if cpuID == -1 { - stat.CPUTotal = cpuStat - } else { - for int64(len(stat.CPU)) <= cpuID { - stat.CPU = append(stat.CPU, CPUStat{}) - } - stat.CPU[cpuID] = cpuStat - } - } - } - - if err := scanner.Err(); err != nil { - return Stat{}, fmt.Errorf("couldn't parse %s: %s", f.Name(), err) - } - - return stat, nil -} diff --git a/vendor/github.com/prometheus/procfs/ttar b/vendor/github.com/prometheus/procfs/ttar deleted file mode 100755 index 8227a4a..0000000 --- a/vendor/github.com/prometheus/procfs/ttar +++ /dev/null @@ -1,264 +0,0 @@ -#!/usr/bin/env bash -# Purpose: plain text tar format -# Limitations: - only suitable for text files, directories, and symlinks -# - stores only filename, content, and mode -# - not designed for untrusted input - -# Note: must work with bash version 3.2 (macOS) - -set -o errexit -o nounset - -# Sanitize environment (for instance, standard sorting of glob matches) -export LC_ALL=C - -path="" -CMD="" - -function usage { - bname=$(basename "$0") - cat << USAGE -Usage: $bname [-C ] -c -f (create archive) - $bname -t -f (list archive contents) - $bname [-C ] -x -f (extract archive) - -Options: - -C (change directory) - -Example: Change to sysfs directory, create ttar file from fixtures directory - $bname -C sysfs -c -f sysfs/fixtures.ttar fixtures/ -USAGE -exit "$1" -} - -function vecho { - if [ "${VERBOSE:-}" == "yes" ]; then - echo >&7 "$@" - fi -} - -function set_cmd { - if [ -n "$CMD" ]; then - echo "ERROR: more than one command given" - echo - usage 2 - fi - CMD=$1 -} - -while getopts :cf:htxvC: opt; do - case $opt in - c) - set_cmd "create" - ;; - f) - ARCHIVE=$OPTARG - ;; - h) - usage 0 - ;; - t) - set_cmd "list" - ;; - x) - set_cmd "extract" - ;; - v) - VERBOSE=yes - exec 7>&1 - ;; - C) - CDIR=$OPTARG - ;; - *) - echo >&2 "ERROR: invalid option -$OPTARG" - echo - usage 1 - ;; - esac -done - -# Remove processed options from arguments -shift $(( OPTIND - 1 )); - -if [ "${CMD:-}" == "" ]; then - echo >&2 "ERROR: no command given" - echo - usage 1 -elif [ "${ARCHIVE:-}" == "" ]; then - echo >&2 "ERROR: no archive name given" - echo - usage 1 -fi - -function list { - local path="" - local size=0 - local line_no=0 - local ttar_file=$1 - if [ -n "${2:-}" ]; then - echo >&2 "ERROR: too many arguments." - echo - usage 1 - fi - if [ ! -e "$ttar_file" ]; then - echo >&2 "ERROR: file not found ($ttar_file)" - echo - usage 1 - fi - while read -r line; do - line_no=$(( line_no + 1 )) - if [ $size -gt 0 ]; then - size=$(( size - 1 )) - continue - fi - if [[ $line =~ ^Path:\ (.*)$ ]]; then - path=${BASH_REMATCH[1]} - elif [[ $line =~ ^Lines:\ (.*)$ ]]; then - size=${BASH_REMATCH[1]} - echo "$path" - elif [[ $line =~ ^Directory:\ (.*)$ ]]; then - path=${BASH_REMATCH[1]} - echo "$path/" - elif [[ $line =~ ^SymlinkTo:\ (.*)$ ]]; then - echo "$path -> ${BASH_REMATCH[1]}" - fi - done < "$ttar_file" -} - -function extract { - local path="" - local size=0 - local line_no=0 - local ttar_file=$1 - if [ -n "${2:-}" ]; then - echo >&2 "ERROR: too many arguments." - echo - usage 1 - fi - if [ ! -e "$ttar_file" ]; then - echo >&2 "ERROR: file not found ($ttar_file)" - echo - usage 1 - fi - while IFS= read -r line; do - line_no=$(( line_no + 1 )) - if [ "$size" -gt 0 ]; then - echo "$line" >> "$path" - size=$(( size - 1 )) - continue - fi - if [[ $line =~ ^Path:\ (.*)$ ]]; then - path=${BASH_REMATCH[1]} - if [ -e "$path" ] || [ -L "$path" ]; then - rm "$path" - fi - elif [[ $line =~ ^Lines:\ (.*)$ ]]; then - size=${BASH_REMATCH[1]} - # Create file even if it is zero-length. - touch "$path" - vecho " $path" - elif [[ $line =~ ^Mode:\ (.*)$ ]]; then - mode=${BASH_REMATCH[1]} - chmod "$mode" "$path" - vecho "$mode" - elif [[ $line =~ ^Directory:\ (.*)$ ]]; then - path=${BASH_REMATCH[1]} - mkdir -p "$path" - vecho " $path/" - elif [[ $line =~ ^SymlinkTo:\ (.*)$ ]]; then - ln -s "${BASH_REMATCH[1]}" "$path" - vecho " $path -> ${BASH_REMATCH[1]}" - elif [[ $line =~ ^# ]]; then - # Ignore comments between files - continue - else - echo >&2 "ERROR: Unknown keyword on line $line_no: $line" - exit 1 - fi - done < "$ttar_file" -} - -function div { - echo "# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -" \ - "- - - - - -" -} - -function get_mode { - local mfile=$1 - if [ -z "${STAT_OPTION:-}" ]; then - if stat -c '%a' "$mfile" >/dev/null 2>&1; then - STAT_OPTION='-c' - STAT_FORMAT='%a' - else - STAT_OPTION='-f' - STAT_FORMAT='%A' - fi - fi - stat "${STAT_OPTION}" "${STAT_FORMAT}" "$mfile" -} - -function _create { - shopt -s nullglob - local mode - while (( "$#" )); do - file=$1 - if [ -L "$file" ]; then - echo "Path: $file" - symlinkTo=$(readlink "$file") - echo "SymlinkTo: $symlinkTo" - vecho " $file -> $symlinkTo" - div - elif [ -d "$file" ]; then - # Strip trailing slash (if there is one) - file=${file%/} - echo "Directory: $file" - mode=$(get_mode "$file") - echo "Mode: $mode" - vecho "$mode $file/" - div - # Find all files and dirs, including hidden/dot files - for x in "$file/"{*,.[^.]*}; do - _create "$x" - done - elif [ -f "$file" ]; then - echo "Path: $file" - lines=$(wc -l "$file"|awk '{print $1}') - echo "Lines: $lines" - cat "$file" - mode=$(get_mode "$file") - echo "Mode: $mode" - vecho "$mode $file" - div - else - echo >&2 "ERROR: file not found ($file in $(pwd))" - exit 2 - fi - shift - done -} - -function create { - ttar_file=$1 - shift - if [ -z "${1:-}" ]; then - echo >&2 "ERROR: missing arguments." - echo - usage 1 - fi - if [ -e "$ttar_file" ]; then - rm "$ttar_file" - fi - exec > "$ttar_file" - _create "$@" -} - -if [ -n "${CDIR:-}" ]; then - if [[ "$ARCHIVE" != /* ]]; then - # Relative path: preserve the archive's location before changing - # directory - ARCHIVE="$(pwd)/$ARCHIVE" - fi - cd "$CDIR" -fi - -"$CMD" "$ARCHIVE" "$@" diff --git a/vendor/github.com/prometheus/procfs/xfrm.go b/vendor/github.com/prometheus/procfs/xfrm.go deleted file mode 100644 index ffe9df5..0000000 --- a/vendor/github.com/prometheus/procfs/xfrm.go +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright 2017 Prometheus Team -// 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. - -package procfs - -import ( - "bufio" - "fmt" - "os" - "strconv" - "strings" -) - -// XfrmStat models the contents of /proc/net/xfrm_stat. -type XfrmStat struct { - // All errors which are not matched by other - XfrmInError int - // No buffer is left - XfrmInBufferError int - // Header Error - XfrmInHdrError int - // No state found - // i.e. either inbound SPI, address, or IPSEC protocol at SA is wrong - XfrmInNoStates int - // Transformation protocol specific error - // e.g. SA Key is wrong - XfrmInStateProtoError int - // Transformation mode specific error - XfrmInStateModeError int - // Sequence error - // e.g. sequence number is out of window - XfrmInStateSeqError int - // State is expired - XfrmInStateExpired int - // State has mismatch option - // e.g. UDP encapsulation type is mismatched - XfrmInStateMismatch int - // State is invalid - XfrmInStateInvalid int - // No matching template for states - // e.g. Inbound SAs are correct but SP rule is wrong - XfrmInTmplMismatch int - // No policy is found for states - // e.g. Inbound SAs are correct but no SP is found - XfrmInNoPols int - // Policy discards - XfrmInPolBlock int - // Policy error - XfrmInPolError int - // All errors which are not matched by others - XfrmOutError int - // Bundle generation error - XfrmOutBundleGenError int - // Bundle check error - XfrmOutBundleCheckError int - // No state was found - XfrmOutNoStates int - // Transformation protocol specific error - XfrmOutStateProtoError int - // Transportation mode specific error - XfrmOutStateModeError int - // Sequence error - // i.e sequence number overflow - XfrmOutStateSeqError int - // State is expired - XfrmOutStateExpired int - // Policy discads - XfrmOutPolBlock int - // Policy is dead - XfrmOutPolDead int - // Policy Error - XfrmOutPolError int - XfrmFwdHdrError int - XfrmOutStateInvalid int - XfrmAcquireError int -} - -// NewXfrmStat reads the xfrm_stat statistics. -func NewXfrmStat() (XfrmStat, error) { - fs, err := NewFS(DefaultMountPoint) - if err != nil { - return XfrmStat{}, err - } - - return fs.NewXfrmStat() -} - -// NewXfrmStat reads the xfrm_stat statistics from the 'proc' filesystem. -func (fs FS) NewXfrmStat() (XfrmStat, error) { - file, err := os.Open(fs.Path("net/xfrm_stat")) - if err != nil { - return XfrmStat{}, err - } - defer file.Close() - - var ( - x = XfrmStat{} - s = bufio.NewScanner(file) - ) - - for s.Scan() { - fields := strings.Fields(s.Text()) - - if len(fields) != 2 { - return XfrmStat{}, fmt.Errorf( - "couldnt parse %s line %s", file.Name(), s.Text()) - } - - name := fields[0] - value, err := strconv.Atoi(fields[1]) - if err != nil { - return XfrmStat{}, err - } - - switch name { - case "XfrmInError": - x.XfrmInError = value - case "XfrmInBufferError": - x.XfrmInBufferError = value - case "XfrmInHdrError": - x.XfrmInHdrError = value - case "XfrmInNoStates": - x.XfrmInNoStates = value - case "XfrmInStateProtoError": - x.XfrmInStateProtoError = value - case "XfrmInStateModeError": - x.XfrmInStateModeError = value - case "XfrmInStateSeqError": - x.XfrmInStateSeqError = value - case "XfrmInStateExpired": - x.XfrmInStateExpired = value - case "XfrmInStateInvalid": - x.XfrmInStateInvalid = value - case "XfrmInTmplMismatch": - x.XfrmInTmplMismatch = value - case "XfrmInNoPols": - x.XfrmInNoPols = value - case "XfrmInPolBlock": - x.XfrmInPolBlock = value - case "XfrmInPolError": - x.XfrmInPolError = value - case "XfrmOutError": - x.XfrmOutError = value - case "XfrmInStateMismatch": - x.XfrmInStateMismatch = value - case "XfrmOutBundleGenError": - x.XfrmOutBundleGenError = value - case "XfrmOutBundleCheckError": - x.XfrmOutBundleCheckError = value - case "XfrmOutNoStates": - x.XfrmOutNoStates = value - case "XfrmOutStateProtoError": - x.XfrmOutStateProtoError = value - case "XfrmOutStateModeError": - x.XfrmOutStateModeError = value - case "XfrmOutStateSeqError": - x.XfrmOutStateSeqError = value - case "XfrmOutStateExpired": - x.XfrmOutStateExpired = value - case "XfrmOutPolBlock": - x.XfrmOutPolBlock = value - case "XfrmOutPolDead": - x.XfrmOutPolDead = value - case "XfrmOutPolError": - x.XfrmOutPolError = value - case "XfrmFwdHdrError": - x.XfrmFwdHdrError = value - case "XfrmOutStateInvalid": - x.XfrmOutStateInvalid = value - case "XfrmAcquireError": - x.XfrmAcquireError = value - } - - } - - return x, s.Err() -} diff --git a/vendor/github.com/prometheus/procfs/xfs/parse.go b/vendor/github.com/prometheus/procfs/xfs/parse.go deleted file mode 100644 index 2bc0ef3..0000000 --- a/vendor/github.com/prometheus/procfs/xfs/parse.go +++ /dev/null @@ -1,330 +0,0 @@ -// Copyright 2017 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. - -package xfs - -import ( - "bufio" - "fmt" - "io" - "strings" - - "github.com/prometheus/procfs/internal/util" -) - -// ParseStats parses a Stats from an input io.Reader, using the format -// found in /proc/fs/xfs/stat. -func ParseStats(r io.Reader) (*Stats, error) { - const ( - // Fields parsed into stats structures. - fieldExtentAlloc = "extent_alloc" - fieldAbt = "abt" - fieldBlkMap = "blk_map" - fieldBmbt = "bmbt" - fieldDir = "dir" - fieldTrans = "trans" - fieldIg = "ig" - fieldLog = "log" - fieldRw = "rw" - fieldAttr = "attr" - fieldIcluster = "icluster" - fieldVnodes = "vnodes" - fieldBuf = "buf" - 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" - ) - - var xfss Stats - - s := bufio.NewScanner(r) - for s.Scan() { - // Expect at least a string label and a single integer value, ex: - // - abt 0 - // - rw 1 2 - ss := strings.Fields(string(s.Bytes())) - if len(ss) < 2 { - continue - } - label := ss[0] - - // Extended precision counters are uint64 values. - if label == fieldXpc { - us, err := util.ParseUint64s(ss[1:]) - if err != nil { - return nil, err - } - - xfss.ExtendedPrecision, err = extendedPrecisionStats(us) - if err != nil { - return nil, err - } - - continue - } - - // All other counters are uint32 values. - us, err := util.ParseUint32s(ss[1:]) - if err != nil { - return nil, err - } - - switch label { - case fieldExtentAlloc: - xfss.ExtentAllocation, err = extentAllocationStats(us) - case fieldAbt: - xfss.AllocationBTree, err = btreeStats(us) - case fieldBlkMap: - xfss.BlockMapping, err = blockMappingStats(us) - case fieldBmbt: - xfss.BlockMapBTree, err = btreeStats(us) - case fieldDir: - xfss.DirectoryOperation, err = directoryOperationStats(us) - case fieldTrans: - xfss.Transaction, err = transactionStats(us) - case fieldIg: - xfss.InodeOperation, err = inodeOperationStats(us) - case fieldLog: - xfss.LogOperation, err = logOperationStats(us) - case fieldRw: - xfss.ReadWrite, err = readWriteStats(us) - case fieldAttr: - xfss.AttributeOperation, err = attributeOperationStats(us) - case fieldIcluster: - xfss.InodeClustering, err = inodeClusteringStats(us) - case fieldVnodes: - xfss.Vnode, err = vnodeStats(us) - case fieldBuf: - xfss.Buffer, err = bufferStats(us) - } - if err != nil { - return nil, err - } - } - - return &xfss, s.Err() -} - -// extentAllocationStats builds an ExtentAllocationStats from a slice of uint32s. -func extentAllocationStats(us []uint32) (ExtentAllocationStats, error) { - if l := len(us); l != 4 { - return ExtentAllocationStats{}, fmt.Errorf("incorrect number of values for XFS extent allocation stats: %d", l) - } - - return ExtentAllocationStats{ - ExtentsAllocated: us[0], - BlocksAllocated: us[1], - ExtentsFreed: us[2], - BlocksFreed: us[3], - }, nil -} - -// btreeStats builds a BTreeStats from a slice of uint32s. -func btreeStats(us []uint32) (BTreeStats, error) { - if l := len(us); l != 4 { - return BTreeStats{}, fmt.Errorf("incorrect number of values for XFS btree stats: %d", l) - } - - return BTreeStats{ - Lookups: us[0], - Compares: us[1], - RecordsInserted: us[2], - RecordsDeleted: us[3], - }, nil -} - -// BlockMappingStat builds a BlockMappingStats from a slice of uint32s. -func blockMappingStats(us []uint32) (BlockMappingStats, error) { - if l := len(us); l != 7 { - return BlockMappingStats{}, fmt.Errorf("incorrect number of values for XFS block mapping stats: %d", l) - } - - return BlockMappingStats{ - Reads: us[0], - Writes: us[1], - Unmaps: us[2], - ExtentListInsertions: us[3], - ExtentListDeletions: us[4], - ExtentListLookups: us[5], - ExtentListCompares: us[6], - }, nil -} - -// DirectoryOperationStats builds a DirectoryOperationStats from a slice of uint32s. -func directoryOperationStats(us []uint32) (DirectoryOperationStats, error) { - if l := len(us); l != 4 { - return DirectoryOperationStats{}, fmt.Errorf("incorrect number of values for XFS directory operation stats: %d", l) - } - - return DirectoryOperationStats{ - Lookups: us[0], - Creates: us[1], - Removes: us[2], - Getdents: us[3], - }, nil -} - -// TransactionStats builds a TransactionStats from a slice of uint32s. -func transactionStats(us []uint32) (TransactionStats, error) { - if l := len(us); l != 3 { - return TransactionStats{}, fmt.Errorf("incorrect number of values for XFS transaction stats: %d", l) - } - - return TransactionStats{ - Sync: us[0], - Async: us[1], - Empty: us[2], - }, nil -} - -// InodeOperationStats builds an InodeOperationStats from a slice of uint32s. -func inodeOperationStats(us []uint32) (InodeOperationStats, error) { - if l := len(us); l != 7 { - return InodeOperationStats{}, fmt.Errorf("incorrect number of values for XFS inode operation stats: %d", l) - } - - return InodeOperationStats{ - Attempts: us[0], - Found: us[1], - Recycle: us[2], - Missed: us[3], - Duplicate: us[4], - Reclaims: us[5], - AttributeChange: us[6], - }, nil -} - -// LogOperationStats builds a LogOperationStats from a slice of uint32s. -func logOperationStats(us []uint32) (LogOperationStats, error) { - if l := len(us); l != 5 { - return LogOperationStats{}, fmt.Errorf("incorrect number of values for XFS log operation stats: %d", l) - } - - return LogOperationStats{ - Writes: us[0], - Blocks: us[1], - NoInternalBuffers: us[2], - Force: us[3], - ForceSleep: us[4], - }, nil -} - -// ReadWriteStats builds a ReadWriteStats from a slice of uint32s. -func readWriteStats(us []uint32) (ReadWriteStats, error) { - if l := len(us); l != 2 { - return ReadWriteStats{}, fmt.Errorf("incorrect number of values for XFS read write stats: %d", l) - } - - return ReadWriteStats{ - Read: us[0], - Write: us[1], - }, nil -} - -// AttributeOperationStats builds an AttributeOperationStats from a slice of uint32s. -func attributeOperationStats(us []uint32) (AttributeOperationStats, error) { - if l := len(us); l != 4 { - return AttributeOperationStats{}, fmt.Errorf("incorrect number of values for XFS attribute operation stats: %d", l) - } - - return AttributeOperationStats{ - Get: us[0], - Set: us[1], - Remove: us[2], - List: us[3], - }, nil -} - -// InodeClusteringStats builds an InodeClusteringStats from a slice of uint32s. -func inodeClusteringStats(us []uint32) (InodeClusteringStats, error) { - if l := len(us); l != 3 { - return InodeClusteringStats{}, fmt.Errorf("incorrect number of values for XFS inode clustering stats: %d", l) - } - - return InodeClusteringStats{ - Iflush: us[0], - Flush: us[1], - FlushInode: us[2], - }, nil -} - -// VnodeStats builds a VnodeStats from a slice of uint32s. -func vnodeStats(us []uint32) (VnodeStats, error) { - // The attribute "Free" appears to not be available on older XFS - // stats versions. Therefore, 7 or 8 elements may appear in - // this slice. - l := len(us) - if l != 7 && l != 8 { - return VnodeStats{}, fmt.Errorf("incorrect number of values for XFS vnode stats: %d", l) - } - - s := VnodeStats{ - Active: us[0], - Allocate: us[1], - Get: us[2], - Hold: us[3], - Release: us[4], - Reclaim: us[5], - Remove: us[6], - } - - // Skip adding free, unless it is present. The zero value will - // be used in place of an actual count. - if l == 7 { - return s, nil - } - - s.Free = us[7] - return s, nil -} - -// BufferStats builds a BufferStats from a slice of uint32s. -func bufferStats(us []uint32) (BufferStats, error) { - if l := len(us); l != 9 { - return BufferStats{}, fmt.Errorf("incorrect number of values for XFS buffer stats: %d", l) - } - - return BufferStats{ - Get: us[0], - Create: us[1], - GetLocked: us[2], - GetLockedWaited: us[3], - BusyLocked: us[4], - MissLocked: us[5], - PageRetries: us[6], - PageFound: us[7], - GetRead: us[8], - }, nil -} - -// ExtendedPrecisionStats builds an ExtendedPrecisionStats from a slice of uint32s. -func extendedPrecisionStats(us []uint64) (ExtendedPrecisionStats, error) { - if l := len(us); l != 3 { - return ExtendedPrecisionStats{}, fmt.Errorf("incorrect number of values for XFS extended precision stats: %d", l) - } - - return ExtendedPrecisionStats{ - FlushBytes: us[0], - WriteBytes: us[1], - ReadBytes: us[2], - }, nil -} diff --git a/vendor/github.com/prometheus/procfs/xfs/xfs.go b/vendor/github.com/prometheus/procfs/xfs/xfs.go deleted file mode 100644 index d86794b..0000000 --- a/vendor/github.com/prometheus/procfs/xfs/xfs.go +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2017 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. - -// Package xfs provides access to statistics exposed by the XFS filesystem. -package xfs - -// Stats contains XFS filesystem runtime statistics, parsed from -// /proc/fs/xfs/stat. -// -// The names and meanings of each statistic were taken from -// http://xfs.org/index.php/Runtime_Stats and xfs_stats.h in the Linux -// kernel source. Most counters are uint32s (same data types used in -// xfs_stats.h), but some of the "extended precision stats" are uint64s. -type Stats struct { - // The name of the filesystem used to source these statistics. - // If empty, this indicates aggregated statistics for all XFS - // filesystems on the host. - Name string - - ExtentAllocation ExtentAllocationStats - AllocationBTree BTreeStats - BlockMapping BlockMappingStats - BlockMapBTree BTreeStats - DirectoryOperation DirectoryOperationStats - Transaction TransactionStats - InodeOperation InodeOperationStats - LogOperation LogOperationStats - ReadWrite ReadWriteStats - AttributeOperation AttributeOperationStats - InodeClustering InodeClusteringStats - Vnode VnodeStats - Buffer BufferStats - ExtendedPrecision ExtendedPrecisionStats -} - -// ExtentAllocationStats contains statistics regarding XFS extent allocations. -type ExtentAllocationStats struct { - ExtentsAllocated uint32 - BlocksAllocated uint32 - ExtentsFreed uint32 - BlocksFreed uint32 -} - -// BTreeStats contains statistics regarding an XFS internal B-tree. -type BTreeStats struct { - Lookups uint32 - Compares uint32 - RecordsInserted uint32 - RecordsDeleted uint32 -} - -// BlockMappingStats contains statistics regarding XFS block maps. -type BlockMappingStats struct { - Reads uint32 - Writes uint32 - Unmaps uint32 - ExtentListInsertions uint32 - ExtentListDeletions uint32 - ExtentListLookups uint32 - ExtentListCompares uint32 -} - -// DirectoryOperationStats contains statistics regarding XFS directory entries. -type DirectoryOperationStats struct { - Lookups uint32 - Creates uint32 - Removes uint32 - Getdents uint32 -} - -// TransactionStats contains statistics regarding XFS metadata transactions. -type TransactionStats struct { - Sync uint32 - Async uint32 - Empty uint32 -} - -// InodeOperationStats contains statistics regarding XFS inode operations. -type InodeOperationStats struct { - Attempts uint32 - Found uint32 - Recycle uint32 - Missed uint32 - Duplicate uint32 - Reclaims uint32 - AttributeChange uint32 -} - -// LogOperationStats contains statistics regarding the XFS log buffer. -type LogOperationStats struct { - Writes uint32 - Blocks uint32 - NoInternalBuffers uint32 - Force uint32 - ForceSleep uint32 -} - -// ReadWriteStats contains statistics regarding the number of read and write -// system calls for XFS filesystems. -type ReadWriteStats struct { - Read uint32 - Write uint32 -} - -// AttributeOperationStats contains statistics regarding manipulation of -// XFS extended file attributes. -type AttributeOperationStats struct { - Get uint32 - Set uint32 - Remove uint32 - List uint32 -} - -// InodeClusteringStats contains statistics regarding XFS inode clustering -// operations. -type InodeClusteringStats struct { - Iflush uint32 - Flush uint32 - FlushInode uint32 -} - -// VnodeStats contains statistics regarding XFS vnode operations. -type VnodeStats struct { - Active uint32 - Allocate uint32 - Get uint32 - Hold uint32 - Release uint32 - Reclaim uint32 - Remove uint32 - Free uint32 -} - -// BufferStats contains statistics regarding XFS read/write I/O buffers. -type BufferStats struct { - Get uint32 - Create uint32 - GetLocked uint32 - GetLockedWaited uint32 - BusyLocked uint32 - MissLocked uint32 - PageRetries uint32 - PageFound uint32 - GetRead uint32 -} - -// ExtendedPrecisionStats contains high precision counters used to track the -// total number of bytes read, written, or flushed, during XFS operations. -type ExtendedPrecisionStats struct { - FlushBytes uint64 - WriteBytes uint64 - ReadBytes uint64 -} From b547122e93128ee6e815461d9ebdd4a1b56b25a5 Mon Sep 17 00:00:00 2001 From: Khanh Pham Date: Fri, 25 Oct 2019 12:06:19 +0700 Subject: [PATCH 2/6] add support go modules --- go.mod | 8 ++++++ go.sum | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 go.mod create mode 100644 go.sum diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..365f01d --- /dev/null +++ b/go.mod @@ -0,0 +1,8 @@ +module github.com/mrpk1906/nvidia-exporter + +go 1.13 + +require ( + github.com/mindprince/gonvml v0.0.0-20190828220739-9ebdce4bb989 + github.com/prometheus/client_golang v1.2.1 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..e33727a --- /dev/null +++ b/go.sum @@ -0,0 +1,78 @@ +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/cespare/xxhash/v2 v2.1.0 h1:yTUvW7Vhb89inJ+8irsUqiWjh8iT6sQPZiQzI6ReGkA= +github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mindprince/gonvml v0.0.0-20190828220739-9ebdce4bb989 h1:PS1dLCGtD8bb9RPKJrc8bS7qHL6JnW1CZvwzH9dPoUs= +github.com/mindprince/gonvml v0.0.0-20190828220739-9ebdce4bb989/go.mod h1:2eu9pRWp8mo84xCg6KswZ+USQHjwgRhNp06sozOdsTY= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.2.1 h1:JnMpQc6ppsNgw9QPAGF6Dod479itz7lvlsMzzNayLOI= +github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8= +github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= From 1a2bb9680a4e339104bc8aba7ebc1009603a70c6 Mon Sep 17 00:00:00 2001 From: Khanh Pham Date: Fri, 25 Oct 2019 12:07:11 +0700 Subject: [PATCH 3/6] Fix bug NVML not found --- Dockerfile | 11 ++++------- Makefile | 4 ++-- main.go | 6 ++++++ metrics.go | 4 ---- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/Dockerfile b/Dockerfile index 17972c1..fae7fbc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,17 +1,14 @@ -FROM golang:1.9.2-alpine3.6 as builder +FROM golang:1.13-alpine3.10 as builder RUN apk add --no-cache make gcc git musl-dev -RUN go get -u github.com/golang/dep/cmd/dep -WORKDIR /go/src/github.com/bugroger/nvidia-exporter +WORKDIR /go/src/github.com/mrpk1906/nvidia-exporter COPY . . -#RUN dep ensure -vendor-only - ARG VERSION RUN make all -FROM alpine +FROM alpine RUN mkdir -p /etc/ld.so.conf.d RUN echo "/usr/local/cuda/lib64" >> /etc/ld.so.conf.d/cuda.conf @@ -20,6 +17,6 @@ RUN echo "/usr/local/nvidia/lib64" >> /etc/ld.so.conf.d/nvidia.conf ENV PATH $PATH:/usr/local/nvidia/bin:/usr/local/cuda/bin ENV LD_LIBRARY_PATH $LD_LIBRARY_PATH:/usr/local/nvidia/lib64/:/usr/local/cuda/lib64/ -COPY --from=builder /go/src/github.com/bugroger/nvidia-exporter/bin/linux/* / +COPY --from=builder /go/src/github.com/mrpk1906/nvidia-exporter/bin/linux/* / ENTRYPOINT ["/nvidia-exporter"] diff --git a/Makefile b/Makefile index 9a8a74f..f50c06f 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,10 @@ DATE = $(shell date +%Y%m%d%H%M) -IMAGE ?= bugroger/nvidia-exporter +IMAGE ?= mrpk1906/nvidia-exporter VERSION := $(DATE) GOOS ?= $(shell go env | grep GOOS | cut -d'"' -f2) BINARIES := nvidia-exporter -LDFLAGS := -X github.com/bugroger/nvidia-exporter/main.VERSION=$(VERSION) +LDFLAGS := -X github.com/mrpk1906/nvidia-exporter/main.VERSION=$(VERSION) GOFLAGS := -ldflags "$(LDFLAGS)" SRCDIRS := . diff --git a/main.go b/main.go index 7e4b1ad..2346f1f 100644 --- a/main.go +++ b/main.go @@ -3,6 +3,7 @@ package main import ( "flag" "fmt" + "github.com/mindprince/gonvml" "log" "net/http" @@ -37,6 +38,11 @@ func main() { ) flag.Parse() + if err := gonvml.Initialize(); err != nil { + log.Fatalf("Couldn't initialize gonvml: %v. Make sure NVML is in the shared library search path.", err) + } + defer gonvml.Shutdown() + prometheus.MustRegister(NewExporter()) http.Handle("/metrics", promhttp.Handler()) diff --git a/metrics.go b/metrics.go index da4f9fe..ac32214 100644 --- a/metrics.go +++ b/metrics.go @@ -33,10 +33,6 @@ type Device struct { } func collectMetrics() (*Metrics, error) { - if err := gonvml.Initialize(); err != nil { - return nil, err - } - defer gonvml.Shutdown() version, err := gonvml.SystemDriverVersion() if err != nil { From 563930c846beb1224166a9e5e1cdef151543c84c Mon Sep 17 00:00:00 2001 From: Khanh Pham Date: Fri, 25 Oct 2019 12:08:26 +0700 Subject: [PATCH 4/6] change gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index c3da290..0672a77 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ .idea/* - +nvidia-exporter From 6365dc95abfda7bbabce361eabb750b4b1d5623d Mon Sep 17 00:00:00 2001 From: Khanh Pham Date: Fri, 25 Oct 2019 13:44:57 +0700 Subject: [PATCH 5/6] add dashboard grafana --- grafana-GPU-dashboard.json | 1119 ++++++++++++++++++++++++++++++++++++ 1 file changed, 1119 insertions(+) create mode 100644 grafana-GPU-dashboard.json diff --git a/grafana-GPU-dashboard.json b/grafana-GPU-dashboard.json new file mode 100644 index 0000000..91a959f --- /dev/null +++ b/grafana-GPU-dashboard.json @@ -0,0 +1,1119 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "GPU dashboard for nvidia metrics ", + "editable": true, + "gnetId": 6387, + "graphTooltip": 1, + "id": 21, + "iteration": 1571985764348, + "links": [], + "panels": [ + { + "columns": [], + "datasource": "Prometheus", + "fontSize": "110%", + "gridPos": { + "h": 3, + "w": 4, + "x": 0, + "y": 0 + }, + "id": 6, + "links": [], + "options": {}, + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Node", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "pattern": "kubernetes_pod_node_name", + "preserveFormat": false, + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "Version", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "version", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "hidden", + "unit": "short" + } + ], + "targets": [ + { + "expr": "nvidia_driver_info{instance=\"$host\",job=\"gpu\"}", + "format": "table", + "instant": true, + "intervalFactor": 1, + "refId": "A" + } + ], + "title": "Driver Version", + "transform": "table", + "type": "table" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#d44a3a", + "rgba(237, 129, 40, 0.89)", + "#299c46" + ], + "datasource": "Prometheus", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 6, + "w": 3, + "x": 4, + "y": 0 + }, + "id": 22, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "%", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(nvidia_utilization_gpu{instance=\"$host\",job=\"gpu\"}) / sum(nvidia_device_count{instance=\"$host\",job=\"gpu\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "title": "GPU Utilization", + "transparent": true, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#d44a3a", + "rgba(237, 129, 40, 0.89)", + "#299c46" + ], + "datasource": "Prometheus", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 6, + "w": 3, + "x": 7, + "y": 0 + }, + "id": 23, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "%", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(nvidia_utilization_memory{instance=\"$host\",job=\"gpu\"}) / sum(nvidia_device_count{instance=\"$host\",job=\"gpu\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "title": "Memory Utilization", + "transparent": true, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 7, + "x": 10, + "y": 0 + }, + "id": 10, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + {} + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "nvidia_utilization_gpu{instance=\"$host\",job=\"gpu\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "gpu{{minor}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "GPU Utilization / Card", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "transparent": true, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percent", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 7, + "x": 17, + "y": 0 + }, + "id": 11, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "nvidia_utilization_memory{instance=\"$host\",job=\"gpu\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "gpu{{minor}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory Utilization / Card", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "transparent": true, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percent", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 2, + "y": 3 + }, + "id": 25, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(nvidia_device_count{instance=\"$host\",job=\"gpu\"})", + "format": "time_series", + "instant": true, + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "title": "# GPUs", + "transparent": true, + "type": "singlestat", + "valueFontSize": "120%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "cacheTimeout": null, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 11, + "x": 0, + "y": 6 + }, + "id": 27, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pluginVersion": "6.2.2", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(nvidia_memory_used{instance=\"$host\",job=\"gpu\"} / nvidia_memory_total{instance=\"$host\",job=\"gpu\"}) * 100", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "gpu{{minor}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory Used (%)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percent", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 4, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 13, + "x": 11, + "y": 6 + }, + "id": 20, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "nvidia_power_usage{instance=\"$host\",job=\"gpu\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": " gpu{{minor}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Power Usage", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "mwatt", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 11, + "x": 0, + "y": 13 + }, + "id": 12, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": false, + "sort": "avg", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "nvidia_fanspeed{instance=\"$host\",job=\"gpu\"}", + "format": "time_series", + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": " gpu{{minor}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Fan Speed", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percent", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "conditions": [ + { + "evaluator": { + "params": [ + 90 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "frequency": "5s", + "handler": 1, + "message": "The GPU temperature is too damn high!", + "name": "GPU Temperature alert", + "noDataState": "no_data", + "notifications": [ + { + "id": 1 + } + ] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 13, + "x": 11, + "y": 13 + }, + "id": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "nvidia_temperatures{instance=\"$host\",job=\"gpu\"}", + "format": "time_series", + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "gpu{{minor}}", + "refId": "A" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 90 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "GPU Temperature", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "celsius", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "30s", + "schemaVersion": 19, + "style": "dark", + "tags": [ + "gpu", + "cluster", + "hardware", + "infrastructure" + ], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "tags": [], + "text": "172.18.5.16", + "value": "172.18.5.16" + }, + "datasource": "Prometheus", + "definition": "label_values(nvidia_up, instance)", + "hide": 0, + "includeAll": false, + "label": "host", + "multi": false, + "name": "host", + "options": [ + { + "selected": true, + "text": "172.18.5.16", + "value": "172.18.5.16" + }, + { + "selected": false, + "text": "172.18.5.17", + "value": "172.18.5.17" + }, + { + "selected": false, + "text": "172.18.5.18", + "value": "172.18.5.18" + }, + { + "selected": false, + "text": "172.18.5.28", + "value": "172.18.5.28" + }, + { + "selected": false, + "text": "172.18.5.29", + "value": "172.18.5.29" + }, + { + "selected": false, + "text": "172.18.5.30", + "value": "172.18.5.30" + }, + { + "selected": false, + "text": "172.18.5.69", + "value": "172.18.5.69" + }, + { + "selected": false, + "text": "172.18.5.70", + "value": "172.18.5.70" + }, + { + "selected": false, + "text": "172.18.5.71", + "value": "172.18.5.71" + }, + { + "selected": false, + "text": "172.18.5.72", + "value": "172.18.5.72" + }, + { + "selected": false, + "text": "172.26.33.174", + "value": "172.26.33.174" + }, + { + "selected": false, + "text": "172.26.33.20", + "value": "172.26.33.20" + }, + { + "selected": false, + "text": "172.26.33.21", + "value": "172.26.33.21" + }, + { + "selected": false, + "text": "172.26.33.22", + "value": "172.26.33.22" + }, + { + "selected": false, + "text": "172.26.33.23", + "value": "172.26.33.23" + }, + { + "selected": false, + "text": "172.26.33.24", + "value": "172.26.33.24" + } + ], + "query": "label_values(nvidia_up, instance)", + "refresh": 0, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "GPU", + "uid": "fnvhnzGmk", + "version": 17 +} \ No newline at end of file From 1668e4a39a1d8a0c916c05df50635dfe9f0dc7fd Mon Sep 17 00:00:00 2001 From: Khanh Pham Date: Fri, 25 Oct 2019 13:49:49 +0700 Subject: [PATCH 6/6] add dashboard example --- README.md | 4 ++++ dashboard-example.png | Bin 0 -> 341631 bytes 2 files changed, 4 insertions(+) create mode 100644 dashboard-example.png diff --git a/README.md b/README.md index c9c88fb..7e60ccf 100644 --- a/README.md +++ b/README.md @@ -149,3 +149,7 @@ nvidia_utilization_memory{minor="3"} 75 nvidia_utilization_memory{minor="4"} 78 nvidia_utilization_memory{minor="5"} 76 ``` + +## Dashboard grafana + +![](dashboard-example.png) diff --git a/dashboard-example.png b/dashboard-example.png new file mode 100644 index 0000000000000000000000000000000000000000..ff5f766a00b4b28afb9020771bc3fb70a4d3a7c1 GIT binary patch literal 341631 zcmd43WmH_t^EOIwcMT2+1h?Ss5Znpw?yds_4;CDPySonVF2P-bySv`W@0|0O_uls; zA1`aon$6zT)!k*gtNQ5)m6sJqf`1DS1_p*CDIuZ=1_mPr1_t2*3k|ws9eltJ2KL6w zTv%9MQdpQo-oe(y+{zdX>_fDno*uO%?S}z^BrUCVT-5b$UktD2z7E)IhQlu-pDv%=r}FE(Ua;9Jk{wjvb2VQ3y>b0yVb2T! zK@RgREmbi!6~Sm1Y=LVKO7y+J4I+tVLrX4L58oT3Fw8fEutsZds-{SfP)J!Cx^ko7fv=LhjZsRZg_2IxcZJA9|QMLU-}6z8ISn4X~GrBQ0GJar8V!>rpXWnDxNXS)<^Tp)a#ZksK&Nq$wzyU7IrqapD z-;i1Ru1-R{lZD~4oOtIz#}BYvWK2`k9DW!-8BeMB&x{^KPxb8@odVqkD} zb)|P@p|^D~WnkjuKoWPJMof{{p#qy{{9-Lv77mS_hjSv_q0G0Wcc-jfr*}x;lFr;n)3X*%O!8_W^AP{ zVr~r*52z15CJr`cp8quXe?9u|F8^w(;%Mw3Y-BRTn0{*-4|9tp=HvCVYpZ~j0 z4i2{e+2#Lu@^?!fhF??vAENk6&i}a!5;Pw?55s>cjSn6e#3lp=CIBWWBB<>4=4b`U z3$yo`|7;wJLj*aV1YH?iRp1R)wi*0avZ4>vVn1NPsn;?1z{-TmCM;^veP(}P{{Xj! zA`ZdcRDu*y_z)5=c20c$CO-Jnmrtm$P{@7|F|V#BE-tt9aPMH@;4-`gO-xNmaNi*anR9Ft~!%_up#sYUfvfRGZPHzgTVjw zGBY1aqt?u?@%stnQo+Ac{>{p+5Q>A*qcHF@|G%;Qn^=AmoB+4%JlL1;-$(HmIdUB+ zP@>c^9{$NdEVO(fa#&wbDI9?Gj~81_5TZz(02Gu z2qTUhQ2l<6e&2BleHfeVl)Hlpb=w7%&NRqU#zU}>Fp)ZCJWw*MUaEa1qh3)C>&613z zF#D1D#^rQX8;PzO?)L(Y12ImVEYodoOUF~Mhs!4z1b_ej{d~PO{=py^70&M&Oot0l zacHQpT!<@|SlE5MK_3>!1anRJ-HbAWpniG(PjTN-rGL!sUrcR=qysN!#&?9`PptPl z)_RB8=tGV3??*46`4;4#8b||HUw$`Y&?pN(gY0~^lwb2tVok!48tCQ%W4q%?~CiwXS|-2F6Y z3~hPpIc-jScPl(Q=nwcbmikLXc-B(TkibKR3nDBDx6 z-G_bs1=f~(wP+CGrcRejEoU|9`y=dF+>4+h`EZ;}4j6eCriSEI;I ziXkCU`%ct|x>wyzZp`$4_`~WfL)jx4fp4jul3etx$%Mwzi#|us

JF<}HO)a^H^6 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 z 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

Oya}P7fZNlpkHytYAeIZ$vRXDIJCLEsuSF3 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∓SQ`fT*Ac(Z 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%0AxjRiLHp@tjZY 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 b5SwgW8cm