mirror of https://github.com/containers/podman.git
Merge pull request #18529 from containers/renovate/github.com-containernetworking-plugins-1.x
fix(deps): update module github.com/containernetworking/plugins to v1.3.0
This commit is contained in:
commit
c4e648faf4
6
go.mod
6
go.mod
|
@ -11,7 +11,7 @@ require (
|
||||||
github.com/checkpoint-restore/go-criu/v6 v6.3.0
|
github.com/checkpoint-restore/go-criu/v6 v6.3.0
|
||||||
github.com/container-orchestrated-devices/container-device-interface v0.5.4
|
github.com/container-orchestrated-devices/container-device-interface v0.5.4
|
||||||
github.com/containernetworking/cni v1.1.2
|
github.com/containernetworking/cni v1.1.2
|
||||||
github.com/containernetworking/plugins v1.2.0
|
github.com/containernetworking/plugins v1.3.0
|
||||||
github.com/containers/buildah v1.30.1-0.20230504052500-e925b5852e07
|
github.com/containers/buildah v1.30.1-0.20230504052500-e925b5852e07
|
||||||
github.com/containers/common v0.53.1-0.20230506101404-3e93a76d461c
|
github.com/containers/common v0.53.1-0.20230506101404-3e93a76d461c
|
||||||
github.com/containers/conmon v2.0.20+incompatible
|
github.com/containers/conmon v2.0.20+incompatible
|
||||||
|
@ -119,7 +119,7 @@ require (
|
||||||
github.com/google/go-cmp v0.5.9 // indirect
|
github.com/google/go-cmp v0.5.9 // indirect
|
||||||
github.com/google/go-containerregistry v0.14.0 // indirect
|
github.com/google/go-containerregistry v0.14.0 // indirect
|
||||||
github.com/google/go-intervals v0.0.2 // indirect
|
github.com/google/go-intervals v0.0.2 // indirect
|
||||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
|
github.com/google/pprof v0.0.0-20230323073829-e72429f035bd // indirect
|
||||||
github.com/google/trillian v1.5.1 // indirect
|
github.com/google/trillian v1.5.1 // indirect
|
||||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||||
|
@ -166,7 +166,7 @@ require (
|
||||||
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
|
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
|
||||||
github.com/transparency-dev/merkle v0.0.1 // indirect
|
github.com/transparency-dev/merkle v0.0.1 // indirect
|
||||||
github.com/vbatts/tar-split v0.11.3 // indirect
|
github.com/vbatts/tar-split v0.11.3 // indirect
|
||||||
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect
|
github.com/vishvananda/netns v0.0.4 // indirect
|
||||||
go.mongodb.org/mongo-driver v1.11.3 // indirect
|
go.mongodb.org/mongo-driver v1.11.3 // indirect
|
||||||
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 // indirect
|
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 // indirect
|
||||||
go.opencensus.io v0.24.0 // indirect
|
go.opencensus.io v0.24.0 // indirect
|
||||||
|
|
12
go.sum
12
go.sum
|
@ -236,8 +236,8 @@ github.com/containernetworking/cni v1.1.2 h1:wtRGZVv7olUHMOqouPpn3cXJWpJgM6+EUl3
|
||||||
github.com/containernetworking/cni v1.1.2/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw=
|
github.com/containernetworking/cni v1.1.2/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw=
|
||||||
github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM=
|
github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM=
|
||||||
github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8=
|
github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8=
|
||||||
github.com/containernetworking/plugins v1.2.0 h1:SWgg3dQG1yzUo4d9iD8cwSVh1VqI+bP7mkPDoSfP9VU=
|
github.com/containernetworking/plugins v1.3.0 h1:QVNXMT6XloyMUoO2wUOqWTC1hWFV62Q6mVDp5H1HnjM=
|
||||||
github.com/containernetworking/plugins v1.2.0/go.mod h1:/VjX4uHecW5vVimFa1wkG4s+r/s9qIfPdqlLF4TW8c4=
|
github.com/containernetworking/plugins v1.3.0/go.mod h1:Pc2wcedTQQCVuROOOaLBPPxrEXqqXBFt3cZ+/yVg6l0=
|
||||||
github.com/containers/buildah v1.30.1-0.20230504052500-e925b5852e07 h1:Bs2sNFh/fSYr4J6JJLFqzyn3dp6HhlA6ewFwRYUpeIE=
|
github.com/containers/buildah v1.30.1-0.20230504052500-e925b5852e07 h1:Bs2sNFh/fSYr4J6JJLFqzyn3dp6HhlA6ewFwRYUpeIE=
|
||||||
github.com/containers/buildah v1.30.1-0.20230504052500-e925b5852e07/go.mod h1:6A/BK0YJLXL8+AqlbceKJrhUT+NtEgsvAc51F7TAllc=
|
github.com/containers/buildah v1.30.1-0.20230504052500-e925b5852e07/go.mod h1:6A/BK0YJLXL8+AqlbceKJrhUT+NtEgsvAc51F7TAllc=
|
||||||
github.com/containers/common v0.53.1-0.20230506101404-3e93a76d461c h1:NPf//8NAa6xjlj62eBbEBabu8LWVqxPRuweNAFCAYxs=
|
github.com/containers/common v0.53.1-0.20230506101404-3e93a76d461c h1:NPf//8NAa6xjlj62eBbEBabu8LWVqxPRuweNAFCAYxs=
|
||||||
|
@ -561,8 +561,9 @@ github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hf
|
||||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
|
|
||||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
|
github.com/google/pprof v0.0.0-20230323073829-e72429f035bd h1:r8yyd+DJDmsUhGrRBxH5Pj7KeFK5l+Y3FsgT8keqKtk=
|
||||||
|
github.com/google/pprof v0.0.0-20230323073829-e72429f035bd/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk=
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||||
|
@ -776,7 +777,6 @@ github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+
|
||||||
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
|
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
|
||||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
|
||||||
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||||
github.com/onsi/ginkgo/v2 v2.9.4 h1:xR7vG4IXt5RWx6FfIjyAtsoMAtnc3C/rFXBBd2AjZwE=
|
github.com/onsi/ginkgo/v2 v2.9.4 h1:xR7vG4IXt5RWx6FfIjyAtsoMAtnc3C/rFXBBd2AjZwE=
|
||||||
github.com/onsi/ginkgo/v2 v2.9.4/go.mod h1:gCQYp2Q+kSoIj7ykSVb9nskRSsR6PUj4AiLywzIhbKM=
|
github.com/onsi/ginkgo/v2 v2.9.4/go.mod h1:gCQYp2Q+kSoIj7ykSVb9nskRSsR6PUj4AiLywzIhbKM=
|
||||||
|
@ -1004,8 +1004,8 @@ github.com/vishvananda/netlink v1.2.1-beta.2/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhg
|
||||||
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
|
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
|
||||||
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
|
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
|
||||||
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||||
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA=
|
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
|
||||||
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||||
github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU=
|
github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU=
|
||||||
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
|
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
|
||||||
github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||||
|
|
|
@ -17,6 +17,7 @@ package profile
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *Profile) decoder() []decoder {
|
func (p *Profile) decoder() []decoder {
|
||||||
|
@ -183,12 +184,13 @@ var profileDecoder = []decoder{
|
||||||
// repeated Location location = 4
|
// repeated Location location = 4
|
||||||
func(b *buffer, m message) error {
|
func(b *buffer, m message) error {
|
||||||
x := new(Location)
|
x := new(Location)
|
||||||
x.Line = make([]Line, 0, 8) // Pre-allocate Line buffer
|
x.Line = b.tmpLines[:0] // Use shared space temporarily
|
||||||
pp := m.(*Profile)
|
pp := m.(*Profile)
|
||||||
pp.Location = append(pp.Location, x)
|
pp.Location = append(pp.Location, x)
|
||||||
err := decodeMessage(b, x)
|
err := decodeMessage(b, x)
|
||||||
var tmp []Line
|
b.tmpLines = x.Line[:0]
|
||||||
x.Line = append(tmp, x.Line...) // Shrink to allocated size
|
// Copy to shrink size and detach from shared space.
|
||||||
|
x.Line = append([]Line(nil), x.Line...)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
// repeated Function function = 5
|
// repeated Function function = 5
|
||||||
|
@ -252,6 +254,14 @@ func (p *Profile) postDecode() error {
|
||||||
} else {
|
} else {
|
||||||
mappings[m.ID] = m
|
mappings[m.ID] = m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this a main linux kernel mapping with a relocation symbol suffix
|
||||||
|
// ("[kernel.kallsyms]_text"), extract said suffix.
|
||||||
|
// It is fairly hacky to handle at this level, but the alternatives appear even worse.
|
||||||
|
if strings.HasPrefix(m.File, "[kernel.kallsyms]") {
|
||||||
|
m.KernelRelocationSymbol = strings.ReplaceAll(m.File, "[kernel.kallsyms]", "")
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
functions := make(map[uint64]*Function, len(p.Function))
|
functions := make(map[uint64]*Function, len(p.Function))
|
||||||
|
@ -298,41 +308,52 @@ func (p *Profile) postDecode() error {
|
||||||
st.Unit, err = getString(p.stringTable, &st.unitX, err)
|
st.Unit, err = getString(p.stringTable, &st.unitX, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pre-allocate space for all locations.
|
||||||
|
numLocations := 0
|
||||||
for _, s := range p.Sample {
|
for _, s := range p.Sample {
|
||||||
labels := make(map[string][]string, len(s.labelX))
|
numLocations += len(s.locationIDX)
|
||||||
numLabels := make(map[string][]int64, len(s.labelX))
|
}
|
||||||
numUnits := make(map[string][]string, len(s.labelX))
|
locBuffer := make([]*Location, numLocations)
|
||||||
for _, l := range s.labelX {
|
|
||||||
var key, value string
|
for _, s := range p.Sample {
|
||||||
key, err = getString(p.stringTable, &l.keyX, err)
|
if len(s.labelX) > 0 {
|
||||||
if l.strX != 0 {
|
labels := make(map[string][]string, len(s.labelX))
|
||||||
value, err = getString(p.stringTable, &l.strX, err)
|
numLabels := make(map[string][]int64, len(s.labelX))
|
||||||
labels[key] = append(labels[key], value)
|
numUnits := make(map[string][]string, len(s.labelX))
|
||||||
} else if l.numX != 0 || l.unitX != 0 {
|
for _, l := range s.labelX {
|
||||||
numValues := numLabels[key]
|
var key, value string
|
||||||
units := numUnits[key]
|
key, err = getString(p.stringTable, &l.keyX, err)
|
||||||
if l.unitX != 0 {
|
if l.strX != 0 {
|
||||||
var unit string
|
value, err = getString(p.stringTable, &l.strX, err)
|
||||||
unit, err = getString(p.stringTable, &l.unitX, err)
|
labels[key] = append(labels[key], value)
|
||||||
units = padStringArray(units, len(numValues))
|
} else if l.numX != 0 || l.unitX != 0 {
|
||||||
numUnits[key] = append(units, unit)
|
numValues := numLabels[key]
|
||||||
}
|
units := numUnits[key]
|
||||||
numLabels[key] = append(numLabels[key], l.numX)
|
if l.unitX != 0 {
|
||||||
}
|
var unit string
|
||||||
}
|
unit, err = getString(p.stringTable, &l.unitX, err)
|
||||||
if len(labels) > 0 {
|
units = padStringArray(units, len(numValues))
|
||||||
s.Label = labels
|
numUnits[key] = append(units, unit)
|
||||||
}
|
}
|
||||||
if len(numLabels) > 0 {
|
numLabels[key] = append(numLabels[key], l.numX)
|
||||||
s.NumLabel = numLabels
|
|
||||||
for key, units := range numUnits {
|
|
||||||
if len(units) > 0 {
|
|
||||||
numUnits[key] = padStringArray(units, len(numLabels[key]))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.NumUnit = numUnits
|
if len(labels) > 0 {
|
||||||
|
s.Label = labels
|
||||||
|
}
|
||||||
|
if len(numLabels) > 0 {
|
||||||
|
s.NumLabel = numLabels
|
||||||
|
for key, units := range numUnits {
|
||||||
|
if len(units) > 0 {
|
||||||
|
numUnits[key] = padStringArray(units, len(numLabels[key]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.NumUnit = numUnits
|
||||||
|
}
|
||||||
}
|
}
|
||||||
s.Location = make([]*Location, len(s.locationIDX))
|
|
||||||
|
s.Location = locBuffer[:len(s.locationIDX)]
|
||||||
|
locBuffer = locBuffer[len(s.locationIDX):]
|
||||||
for i, lid := range s.locationIDX {
|
for i, lid := range s.locationIDX {
|
||||||
if lid < uint64(len(locationIds)) {
|
if lid < uint64(len(locationIds)) {
|
||||||
s.Location[i] = locationIds[lid]
|
s.Location[i] = locationIds[lid]
|
||||||
|
|
|
@ -22,6 +22,10 @@ import "regexp"
|
||||||
// samples where at least one frame matches focus but none match ignore.
|
// samples where at least one frame matches focus but none match ignore.
|
||||||
// Returns true is the corresponding regexp matched at least one sample.
|
// Returns true is the corresponding regexp matched at least one sample.
|
||||||
func (p *Profile) FilterSamplesByName(focus, ignore, hide, show *regexp.Regexp) (fm, im, hm, hnm bool) {
|
func (p *Profile) FilterSamplesByName(focus, ignore, hide, show *regexp.Regexp) (fm, im, hm, hnm bool) {
|
||||||
|
if focus == nil && ignore == nil && hide == nil && show == nil {
|
||||||
|
fm = true // Missing focus implies a match
|
||||||
|
return
|
||||||
|
}
|
||||||
focusOrIgnore := make(map[uint64]bool)
|
focusOrIgnore := make(map[uint64]bool)
|
||||||
hidden := make(map[uint64]bool)
|
hidden := make(map[uint64]bool)
|
||||||
for _, l := range p.Location {
|
for _, l := range p.Location {
|
||||||
|
|
|
@ -295,11 +295,12 @@ func get64b(b []byte) (uint64, []byte) {
|
||||||
//
|
//
|
||||||
// The general format for profilez samples is a sequence of words in
|
// The general format for profilez samples is a sequence of words in
|
||||||
// binary format. The first words are a header with the following data:
|
// binary format. The first words are a header with the following data:
|
||||||
// 1st word -- 0
|
//
|
||||||
// 2nd word -- 3
|
// 1st word -- 0
|
||||||
// 3rd word -- 0 if a c++ application, 1 if a java application.
|
// 2nd word -- 3
|
||||||
// 4th word -- Sampling period (in microseconds).
|
// 3rd word -- 0 if a c++ application, 1 if a java application.
|
||||||
// 5th word -- Padding.
|
// 4th word -- Sampling period (in microseconds).
|
||||||
|
// 5th word -- Padding.
|
||||||
func parseCPU(b []byte) (*Profile, error) {
|
func parseCPU(b []byte) (*Profile, error) {
|
||||||
var parse func([]byte) (uint64, []byte)
|
var parse func([]byte) (uint64, []byte)
|
||||||
var n1, n2, n3, n4, n5 uint64
|
var n1, n2, n3, n4, n5 uint64
|
||||||
|
@ -403,15 +404,18 @@ func cleanupDuplicateLocations(p *Profile) {
|
||||||
//
|
//
|
||||||
// profilez samples are a repeated sequence of stack frames of the
|
// profilez samples are a repeated sequence of stack frames of the
|
||||||
// form:
|
// form:
|
||||||
// 1st word -- The number of times this stack was encountered.
|
//
|
||||||
// 2nd word -- The size of the stack (StackSize).
|
// 1st word -- The number of times this stack was encountered.
|
||||||
// 3rd word -- The first address on the stack.
|
// 2nd word -- The size of the stack (StackSize).
|
||||||
// ...
|
// 3rd word -- The first address on the stack.
|
||||||
// StackSize + 2 -- The last address on the stack
|
// ...
|
||||||
|
// StackSize + 2 -- The last address on the stack
|
||||||
|
//
|
||||||
// The last stack trace is of the form:
|
// The last stack trace is of the form:
|
||||||
// 1st word -- 0
|
//
|
||||||
// 2nd word -- 1
|
// 1st word -- 0
|
||||||
// 3rd word -- 0
|
// 2nd word -- 1
|
||||||
|
// 3rd word -- 0
|
||||||
//
|
//
|
||||||
// Addresses from stack traces may point to the next instruction after
|
// Addresses from stack traces may point to the next instruction after
|
||||||
// each call. Optionally adjust by -1 to land somewhere on the actual
|
// each call. Optionally adjust by -1 to land somewhere on the actual
|
||||||
|
@ -861,7 +865,6 @@ func parseThread(b []byte) (*Profile, error) {
|
||||||
// Recognize each thread and populate profile samples.
|
// Recognize each thread and populate profile samples.
|
||||||
for !isMemoryMapSentinel(line) {
|
for !isMemoryMapSentinel(line) {
|
||||||
if strings.HasPrefix(line, "---- no stack trace for") {
|
if strings.HasPrefix(line, "---- no stack trace for") {
|
||||||
line = ""
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if t := threadStartRE.FindStringSubmatch(line); len(t) != 4 {
|
if t := threadStartRE.FindStringSubmatch(line); len(t) != 4 {
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
package profile
|
package profile
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -58,7 +59,7 @@ func Merge(srcs []*Profile) (*Profile, error) {
|
||||||
|
|
||||||
for _, src := range srcs {
|
for _, src := range srcs {
|
||||||
// Clear the profile-specific hash tables
|
// Clear the profile-specific hash tables
|
||||||
pm.locationsByID = make(map[uint64]*Location, len(src.Location))
|
pm.locationsByID = makeLocationIDMap(len(src.Location))
|
||||||
pm.functionsByID = make(map[uint64]*Function, len(src.Function))
|
pm.functionsByID = make(map[uint64]*Function, len(src.Function))
|
||||||
pm.mappingsByID = make(map[uint64]mapInfo, len(src.Mapping))
|
pm.mappingsByID = make(map[uint64]mapInfo, len(src.Mapping))
|
||||||
|
|
||||||
|
@ -136,7 +137,7 @@ type profileMerger struct {
|
||||||
p *Profile
|
p *Profile
|
||||||
|
|
||||||
// Memoization tables within a profile.
|
// Memoization tables within a profile.
|
||||||
locationsByID map[uint64]*Location
|
locationsByID locationIDMap
|
||||||
functionsByID map[uint64]*Function
|
functionsByID map[uint64]*Function
|
||||||
mappingsByID map[uint64]mapInfo
|
mappingsByID map[uint64]mapInfo
|
||||||
|
|
||||||
|
@ -153,6 +154,16 @@ type mapInfo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pm *profileMerger) mapSample(src *Sample) *Sample {
|
func (pm *profileMerger) mapSample(src *Sample) *Sample {
|
||||||
|
// Check memoization table
|
||||||
|
k := pm.sampleKey(src)
|
||||||
|
if ss, ok := pm.samples[k]; ok {
|
||||||
|
for i, v := range src.Value {
|
||||||
|
ss.Value[i] += v
|
||||||
|
}
|
||||||
|
return ss
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make new sample.
|
||||||
s := &Sample{
|
s := &Sample{
|
||||||
Location: make([]*Location, len(src.Location)),
|
Location: make([]*Location, len(src.Location)),
|
||||||
Value: make([]int64, len(src.Value)),
|
Value: make([]int64, len(src.Value)),
|
||||||
|
@ -177,52 +188,98 @@ func (pm *profileMerger) mapSample(src *Sample) *Sample {
|
||||||
s.NumLabel[k] = vv
|
s.NumLabel[k] = vv
|
||||||
s.NumUnit[k] = uu
|
s.NumUnit[k] = uu
|
||||||
}
|
}
|
||||||
// Check memoization table. Must be done on the remapped location to
|
|
||||||
// account for the remapped mapping. Add current values to the
|
|
||||||
// existing sample.
|
|
||||||
k := s.key()
|
|
||||||
if ss, ok := pm.samples[k]; ok {
|
|
||||||
for i, v := range src.Value {
|
|
||||||
ss.Value[i] += v
|
|
||||||
}
|
|
||||||
return ss
|
|
||||||
}
|
|
||||||
copy(s.Value, src.Value)
|
copy(s.Value, src.Value)
|
||||||
pm.samples[k] = s
|
pm.samples[k] = s
|
||||||
pm.p.Sample = append(pm.p.Sample, s)
|
pm.p.Sample = append(pm.p.Sample, s)
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// key generates sampleKey to be used as a key for maps.
|
func (pm *profileMerger) sampleKey(sample *Sample) sampleKey {
|
||||||
func (sample *Sample) key() sampleKey {
|
// Accumulate contents into a string.
|
||||||
ids := make([]string, len(sample.Location))
|
var buf strings.Builder
|
||||||
for i, l := range sample.Location {
|
buf.Grow(64) // Heuristic to avoid extra allocs
|
||||||
ids[i] = strconv.FormatUint(l.ID, 16)
|
|
||||||
|
// encode a number
|
||||||
|
putNumber := func(v uint64) {
|
||||||
|
var num [binary.MaxVarintLen64]byte
|
||||||
|
n := binary.PutUvarint(num[:], v)
|
||||||
|
buf.Write(num[:n])
|
||||||
}
|
}
|
||||||
|
|
||||||
labels := make([]string, 0, len(sample.Label))
|
// encode a string prefixed with its length.
|
||||||
for k, v := range sample.Label {
|
putDelimitedString := func(s string) {
|
||||||
labels = append(labels, fmt.Sprintf("%q%q", k, v))
|
putNumber(uint64(len(s)))
|
||||||
|
buf.WriteString(s)
|
||||||
}
|
}
|
||||||
sort.Strings(labels)
|
|
||||||
|
|
||||||
numlabels := make([]string, 0, len(sample.NumLabel))
|
for _, l := range sample.Location {
|
||||||
for k, v := range sample.NumLabel {
|
// Get the location in the merged profile, which may have a different ID.
|
||||||
numlabels = append(numlabels, fmt.Sprintf("%q%x%x", k, v, sample.NumUnit[k]))
|
if loc := pm.mapLocation(l); loc != nil {
|
||||||
|
putNumber(loc.ID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sort.Strings(numlabels)
|
putNumber(0) // Delimiter
|
||||||
|
|
||||||
return sampleKey{
|
for _, l := range sortedKeys1(sample.Label) {
|
||||||
strings.Join(ids, "|"),
|
putDelimitedString(l)
|
||||||
strings.Join(labels, ""),
|
values := sample.Label[l]
|
||||||
strings.Join(numlabels, ""),
|
putNumber(uint64(len(values)))
|
||||||
|
for _, v := range values {
|
||||||
|
putDelimitedString(v)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, l := range sortedKeys2(sample.NumLabel) {
|
||||||
|
putDelimitedString(l)
|
||||||
|
values := sample.NumLabel[l]
|
||||||
|
putNumber(uint64(len(values)))
|
||||||
|
for _, v := range values {
|
||||||
|
putNumber(uint64(v))
|
||||||
|
}
|
||||||
|
units := sample.NumUnit[l]
|
||||||
|
putNumber(uint64(len(units)))
|
||||||
|
for _, v := range units {
|
||||||
|
putDelimitedString(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sampleKey(buf.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
type sampleKey struct {
|
type sampleKey string
|
||||||
locations string
|
|
||||||
labels string
|
// sortedKeys1 returns the sorted keys found in a string->[]string map.
|
||||||
numlabels string
|
//
|
||||||
|
// Note: this is currently non-generic since github pprof runs golint,
|
||||||
|
// which does not support generics. When that issue is fixed, it can
|
||||||
|
// be merged with sortedKeys2 and made into a generic function.
|
||||||
|
func sortedKeys1(m map[string][]string) []string {
|
||||||
|
if len(m) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
keys := make([]string, 0, len(m))
|
||||||
|
for k := range m {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
|
||||||
|
// sortedKeys2 returns the sorted keys found in a string->[]int64 map.
|
||||||
|
//
|
||||||
|
// Note: this is currently non-generic since github pprof runs golint,
|
||||||
|
// which does not support generics. When that issue is fixed, it can
|
||||||
|
// be merged with sortedKeys1 and made into a generic function.
|
||||||
|
func sortedKeys2(m map[string][]int64) []string {
|
||||||
|
if len(m) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
keys := make([]string, 0, len(m))
|
||||||
|
for k := range m {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
return keys
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pm *profileMerger) mapLocation(src *Location) *Location {
|
func (pm *profileMerger) mapLocation(src *Location) *Location {
|
||||||
|
@ -230,7 +287,7 @@ func (pm *profileMerger) mapLocation(src *Location) *Location {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if l, ok := pm.locationsByID[src.ID]; ok {
|
if l := pm.locationsByID.get(src.ID); l != nil {
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,10 +306,10 @@ func (pm *profileMerger) mapLocation(src *Location) *Location {
|
||||||
// account for the remapped mapping ID.
|
// account for the remapped mapping ID.
|
||||||
k := l.key()
|
k := l.key()
|
||||||
if ll, ok := pm.locations[k]; ok {
|
if ll, ok := pm.locations[k]; ok {
|
||||||
pm.locationsByID[src.ID] = ll
|
pm.locationsByID.set(src.ID, ll)
|
||||||
return ll
|
return ll
|
||||||
}
|
}
|
||||||
pm.locationsByID[src.ID] = l
|
pm.locationsByID.set(src.ID, l)
|
||||||
pm.locations[k] = l
|
pm.locations[k] = l
|
||||||
pm.p.Location = append(pm.p.Location, l)
|
pm.p.Location = append(pm.p.Location, l)
|
||||||
return l
|
return l
|
||||||
|
@ -303,16 +360,17 @@ func (pm *profileMerger) mapMapping(src *Mapping) mapInfo {
|
||||||
return mi
|
return mi
|
||||||
}
|
}
|
||||||
m := &Mapping{
|
m := &Mapping{
|
||||||
ID: uint64(len(pm.p.Mapping) + 1),
|
ID: uint64(len(pm.p.Mapping) + 1),
|
||||||
Start: src.Start,
|
Start: src.Start,
|
||||||
Limit: src.Limit,
|
Limit: src.Limit,
|
||||||
Offset: src.Offset,
|
Offset: src.Offset,
|
||||||
File: src.File,
|
File: src.File,
|
||||||
BuildID: src.BuildID,
|
KernelRelocationSymbol: src.KernelRelocationSymbol,
|
||||||
HasFunctions: src.HasFunctions,
|
BuildID: src.BuildID,
|
||||||
HasFilenames: src.HasFilenames,
|
HasFunctions: src.HasFunctions,
|
||||||
HasLineNumbers: src.HasLineNumbers,
|
HasFilenames: src.HasFilenames,
|
||||||
HasInlineFrames: src.HasInlineFrames,
|
HasLineNumbers: src.HasLineNumbers,
|
||||||
|
HasInlineFrames: src.HasInlineFrames,
|
||||||
}
|
}
|
||||||
pm.p.Mapping = append(pm.p.Mapping, m)
|
pm.p.Mapping = append(pm.p.Mapping, m)
|
||||||
|
|
||||||
|
@ -479,3 +537,131 @@ func (p *Profile) compatible(pb *Profile) error {
|
||||||
func equalValueType(st1, st2 *ValueType) bool {
|
func equalValueType(st1, st2 *ValueType) bool {
|
||||||
return st1.Type == st2.Type && st1.Unit == st2.Unit
|
return st1.Type == st2.Type && st1.Unit == st2.Unit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// locationIDMap is like a map[uint64]*Location, but provides efficiency for
|
||||||
|
// ids that are densely numbered, which is often the case.
|
||||||
|
type locationIDMap struct {
|
||||||
|
dense []*Location // indexed by id for id < len(dense)
|
||||||
|
sparse map[uint64]*Location // indexed by id for id >= len(dense)
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeLocationIDMap(n int) locationIDMap {
|
||||||
|
return locationIDMap{
|
||||||
|
dense: make([]*Location, n),
|
||||||
|
sparse: map[uint64]*Location{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lm locationIDMap) get(id uint64) *Location {
|
||||||
|
if id < uint64(len(lm.dense)) {
|
||||||
|
return lm.dense[int(id)]
|
||||||
|
}
|
||||||
|
return lm.sparse[id]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lm locationIDMap) set(id uint64, loc *Location) {
|
||||||
|
if id < uint64(len(lm.dense)) {
|
||||||
|
lm.dense[id] = loc
|
||||||
|
return
|
||||||
|
}
|
||||||
|
lm.sparse[id] = loc
|
||||||
|
}
|
||||||
|
|
||||||
|
// CompatibilizeSampleTypes makes profiles compatible to be compared/merged. It
|
||||||
|
// keeps sample types that appear in all profiles only and drops/reorders the
|
||||||
|
// sample types as necessary.
|
||||||
|
//
|
||||||
|
// In the case of sample types order is not the same for given profiles the
|
||||||
|
// order is derived from the first profile.
|
||||||
|
//
|
||||||
|
// Profiles are modified in-place.
|
||||||
|
//
|
||||||
|
// It returns an error if the sample type's intersection is empty.
|
||||||
|
func CompatibilizeSampleTypes(ps []*Profile) error {
|
||||||
|
sTypes := commonSampleTypes(ps)
|
||||||
|
if len(sTypes) == 0 {
|
||||||
|
return fmt.Errorf("profiles have empty common sample type list")
|
||||||
|
}
|
||||||
|
for _, p := range ps {
|
||||||
|
if err := compatibilizeSampleTypes(p, sTypes); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// commonSampleTypes returns sample types that appear in all profiles in the
|
||||||
|
// order how they ordered in the first profile.
|
||||||
|
func commonSampleTypes(ps []*Profile) []string {
|
||||||
|
if len(ps) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
sTypes := map[string]int{}
|
||||||
|
for _, p := range ps {
|
||||||
|
for _, st := range p.SampleType {
|
||||||
|
sTypes[st.Type]++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var res []string
|
||||||
|
for _, st := range ps[0].SampleType {
|
||||||
|
if sTypes[st.Type] == len(ps) {
|
||||||
|
res = append(res, st.Type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// compatibilizeSampleTypes drops sample types that are not present in sTypes
|
||||||
|
// list and reorder them if needed.
|
||||||
|
//
|
||||||
|
// It sets DefaultSampleType to sType[0] if it is not in sType list.
|
||||||
|
//
|
||||||
|
// It assumes that all sample types from the sTypes list are present in the
|
||||||
|
// given profile otherwise it returns an error.
|
||||||
|
func compatibilizeSampleTypes(p *Profile, sTypes []string) error {
|
||||||
|
if len(sTypes) == 0 {
|
||||||
|
return fmt.Errorf("sample type list is empty")
|
||||||
|
}
|
||||||
|
defaultSampleType := sTypes[0]
|
||||||
|
reMap, needToModify := make([]int, len(sTypes)), false
|
||||||
|
for i, st := range sTypes {
|
||||||
|
if st == p.DefaultSampleType {
|
||||||
|
defaultSampleType = p.DefaultSampleType
|
||||||
|
}
|
||||||
|
idx := searchValueType(p.SampleType, st)
|
||||||
|
if idx < 0 {
|
||||||
|
return fmt.Errorf("%q sample type is not found in profile", st)
|
||||||
|
}
|
||||||
|
reMap[i] = idx
|
||||||
|
if idx != i {
|
||||||
|
needToModify = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !needToModify && len(sTypes) == len(p.SampleType) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
p.DefaultSampleType = defaultSampleType
|
||||||
|
oldSampleTypes := p.SampleType
|
||||||
|
p.SampleType = make([]*ValueType, len(sTypes))
|
||||||
|
for i, idx := range reMap {
|
||||||
|
p.SampleType[i] = oldSampleTypes[idx]
|
||||||
|
}
|
||||||
|
values := make([]int64, len(sTypes))
|
||||||
|
for _, s := range p.Sample {
|
||||||
|
for i, idx := range reMap {
|
||||||
|
values[i] = s.Value[idx]
|
||||||
|
}
|
||||||
|
s.Value = s.Value[:len(values)]
|
||||||
|
copy(s.Value, values)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func searchValueType(vts []*ValueType, s string) int {
|
||||||
|
for i, vt := range vts {
|
||||||
|
if vt.Type == s {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
|
@ -21,7 +21,6 @@ import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"math"
|
"math"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
@ -73,9 +72,23 @@ type ValueType struct {
|
||||||
type Sample struct {
|
type Sample struct {
|
||||||
Location []*Location
|
Location []*Location
|
||||||
Value []int64
|
Value []int64
|
||||||
Label map[string][]string
|
// Label is a per-label-key map to values for string labels.
|
||||||
|
//
|
||||||
|
// In general, having multiple values for the given label key is strongly
|
||||||
|
// discouraged - see docs for the sample label field in profile.proto. The
|
||||||
|
// main reason this unlikely state is tracked here is to make the
|
||||||
|
// decoding->encoding roundtrip not lossy. But we expect that the value
|
||||||
|
// slices present in this map are always of length 1.
|
||||||
|
Label map[string][]string
|
||||||
|
// NumLabel is a per-label-key map to values for numeric labels. See a note
|
||||||
|
// above on handling multiple values for a label.
|
||||||
NumLabel map[string][]int64
|
NumLabel map[string][]int64
|
||||||
NumUnit map[string][]string
|
// NumUnit is a per-label-key map to the unit names of corresponding numeric
|
||||||
|
// label values. The unit info may be missing even if the label is in
|
||||||
|
// NumLabel, see the docs in profile.proto for details. When the value is
|
||||||
|
// slice is present and not nil, its length must be equal to the length of
|
||||||
|
// the corresponding value slice in NumLabel.
|
||||||
|
NumUnit map[string][]string
|
||||||
|
|
||||||
locationIDX []uint64
|
locationIDX []uint64
|
||||||
labelX []label
|
labelX []label
|
||||||
|
@ -106,6 +119,15 @@ type Mapping struct {
|
||||||
|
|
||||||
fileX int64
|
fileX int64
|
||||||
buildIDX int64
|
buildIDX int64
|
||||||
|
|
||||||
|
// Name of the kernel relocation symbol ("_text" or "_stext"), extracted from File.
|
||||||
|
// For linux kernel mappings generated by some tools, correct symbolization depends
|
||||||
|
// on knowing which of the two possible relocation symbols was used for `Start`.
|
||||||
|
// This is given to us as a suffix in `File` (e.g. "[kernel.kallsyms]_stext").
|
||||||
|
//
|
||||||
|
// Note, this public field is not persisted in the proto. For the purposes of
|
||||||
|
// copying / merging / hashing profiles, it is considered subsumed by `File`.
|
||||||
|
KernelRelocationSymbol string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Location corresponds to Profile.Location
|
// Location corresponds to Profile.Location
|
||||||
|
@ -144,7 +166,7 @@ type Function struct {
|
||||||
// may be a gzip-compressed encoded protobuf or one of many legacy
|
// may be a gzip-compressed encoded protobuf or one of many legacy
|
||||||
// profile formats which may be unsupported in the future.
|
// profile formats which may be unsupported in the future.
|
||||||
func Parse(r io.Reader) (*Profile, error) {
|
func Parse(r io.Reader) (*Profile, error) {
|
||||||
data, err := ioutil.ReadAll(r)
|
data, err := io.ReadAll(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -159,7 +181,7 @@ func ParseData(data []byte) (*Profile, error) {
|
||||||
if len(data) >= 2 && data[0] == 0x1f && data[1] == 0x8b {
|
if len(data) >= 2 && data[0] == 0x1f && data[1] == 0x8b {
|
||||||
gz, err := gzip.NewReader(bytes.NewBuffer(data))
|
gz, err := gzip.NewReader(bytes.NewBuffer(data))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
data, err = ioutil.ReadAll(gz)
|
data, err = io.ReadAll(gz)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("decompressing profile: %v", err)
|
return nil, fmt.Errorf("decompressing profile: %v", err)
|
||||||
|
@ -707,6 +729,35 @@ func (s *Sample) HasLabel(key, value string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetNumLabel sets the specified key to the specified value for all samples in the
|
||||||
|
// profile. "unit" is a slice that describes the units that each corresponding member
|
||||||
|
// of "values" is measured in (e.g. bytes or seconds). If there is no relevant
|
||||||
|
// unit for a given value, that member of "unit" should be the empty string.
|
||||||
|
// "unit" must either have the same length as "value", or be nil.
|
||||||
|
func (p *Profile) SetNumLabel(key string, value []int64, unit []string) {
|
||||||
|
for _, sample := range p.Sample {
|
||||||
|
if sample.NumLabel == nil {
|
||||||
|
sample.NumLabel = map[string][]int64{key: value}
|
||||||
|
} else {
|
||||||
|
sample.NumLabel[key] = value
|
||||||
|
}
|
||||||
|
if sample.NumUnit == nil {
|
||||||
|
sample.NumUnit = map[string][]string{key: unit}
|
||||||
|
} else {
|
||||||
|
sample.NumUnit[key] = unit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveNumLabel removes all numerical labels associated with the specified key for all
|
||||||
|
// samples in the profile.
|
||||||
|
func (p *Profile) RemoveNumLabel(key string) {
|
||||||
|
for _, sample := range p.Sample {
|
||||||
|
delete(sample.NumLabel, key)
|
||||||
|
delete(sample.NumUnit, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// DiffBaseSample returns true if a sample belongs to the diff base and false
|
// DiffBaseSample returns true if a sample belongs to the diff base and false
|
||||||
// otherwise.
|
// otherwise.
|
||||||
func (s *Sample) DiffBaseSample() bool {
|
func (s *Sample) DiffBaseSample() bool {
|
||||||
|
|
|
@ -39,11 +39,12 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type buffer struct {
|
type buffer struct {
|
||||||
field int // field tag
|
field int // field tag
|
||||||
typ int // proto wire type code for field
|
typ int // proto wire type code for field
|
||||||
u64 uint64
|
u64 uint64
|
||||||
data []byte
|
data []byte
|
||||||
tmp [16]byte
|
tmp [16]byte
|
||||||
|
tmpLines []Line // temporary storage used while decoding "repeated Line".
|
||||||
}
|
}
|
||||||
|
|
||||||
type decoder func(*buffer, message) error
|
type decoder func(*buffer, message) error
|
||||||
|
@ -286,7 +287,6 @@ func decodeInt64s(b *buffer, x *[]int64) error {
|
||||||
if b.typ == 2 {
|
if b.typ == 2 {
|
||||||
// Packed encoding
|
// Packed encoding
|
||||||
data := b.data
|
data := b.data
|
||||||
tmp := make([]int64, 0, len(data)) // Maximally sized
|
|
||||||
for len(data) > 0 {
|
for len(data) > 0 {
|
||||||
var u uint64
|
var u uint64
|
||||||
var err error
|
var err error
|
||||||
|
@ -294,9 +294,8 @@ func decodeInt64s(b *buffer, x *[]int64) error {
|
||||||
if u, data, err = decodeVarint(data); err != nil {
|
if u, data, err = decodeVarint(data); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
tmp = append(tmp, int64(u))
|
*x = append(*x, int64(u))
|
||||||
}
|
}
|
||||||
*x = append(*x, tmp...)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
var i int64
|
var i int64
|
||||||
|
@ -319,7 +318,6 @@ func decodeUint64s(b *buffer, x *[]uint64) error {
|
||||||
if b.typ == 2 {
|
if b.typ == 2 {
|
||||||
data := b.data
|
data := b.data
|
||||||
// Packed encoding
|
// Packed encoding
|
||||||
tmp := make([]uint64, 0, len(data)) // Maximally sized
|
|
||||||
for len(data) > 0 {
|
for len(data) > 0 {
|
||||||
var u uint64
|
var u uint64
|
||||||
var err error
|
var err error
|
||||||
|
@ -327,9 +325,8 @@ func decodeUint64s(b *buffer, x *[]uint64) error {
|
||||||
if u, data, err = decodeVarint(data); err != nil {
|
if u, data, err = decodeVarint(data); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
tmp = append(tmp, u)
|
*x = append(*x, u)
|
||||||
}
|
}
|
||||||
*x = append(*x, tmp...)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
var u uint64
|
var u uint64
|
||||||
|
|
|
@ -62,15 +62,31 @@ func (p *Profile) Prune(dropRx, keepRx *regexp.Regexp) {
|
||||||
prune := make(map[uint64]bool)
|
prune := make(map[uint64]bool)
|
||||||
pruneBeneath := make(map[uint64]bool)
|
pruneBeneath := make(map[uint64]bool)
|
||||||
|
|
||||||
|
// simplifyFunc can be expensive, so cache results.
|
||||||
|
// Note that the same function name can be encountered many times due
|
||||||
|
// different lines and addresses in the same function.
|
||||||
|
pruneCache := map[string]bool{} // Map from function to whether or not to prune
|
||||||
|
pruneFromHere := func(s string) bool {
|
||||||
|
if r, ok := pruneCache[s]; ok {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
funcName := simplifyFunc(s)
|
||||||
|
if dropRx.MatchString(funcName) {
|
||||||
|
if keepRx == nil || !keepRx.MatchString(funcName) {
|
||||||
|
pruneCache[s] = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pruneCache[s] = false
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
for _, loc := range p.Location {
|
for _, loc := range p.Location {
|
||||||
var i int
|
var i int
|
||||||
for i = len(loc.Line) - 1; i >= 0; i-- {
|
for i = len(loc.Line) - 1; i >= 0; i-- {
|
||||||
if fn := loc.Line[i].Function; fn != nil && fn.Name != "" {
|
if fn := loc.Line[i].Function; fn != nil && fn.Name != "" {
|
||||||
funcName := simplifyFunc(fn.Name)
|
if pruneFromHere(fn.Name) {
|
||||||
if dropRx.MatchString(funcName) {
|
break
|
||||||
if keepRx == nil || !keepRx.MatchString(funcName) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
run:
|
||||||
|
timeout: 5m
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"github.com/vishvananda/netns"
|
"github.com/vishvananda/netns"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -48,14 +49,3 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## NOTE
|
|
||||||
|
|
||||||
The library can be safely used only with Go >= 1.10 due to [golang/go#20676](https://github.com/golang/go/issues/20676).
|
|
||||||
|
|
||||||
After locking a goroutine to its current OS thread with `runtime.LockOSThread()`
|
|
||||||
and changing its network namespace, any new subsequent goroutine won't be
|
|
||||||
scheduled on that thread while it's locked. Therefore, the new goroutine
|
|
||||||
will run in a different namespace leading to unexpected results.
|
|
||||||
|
|
||||||
See [here](https://www.weave.works/blog/linux-namespaces-golang-followup) for more details.
|
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
// Package netns allows ultra-simple network namespace handling. NsHandles
|
||||||
|
// can be retrieved and set. Note that the current namespace is thread
|
||||||
|
// local so actions that set and reset namespaces should use LockOSThread
|
||||||
|
// to make sure the namespace doesn't change due to a goroutine switch.
|
||||||
|
// It is best to close NsHandles when you are done with them. This can be
|
||||||
|
// accomplished via a `defer ns.Close()` on the handle. Changing namespaces
|
||||||
|
// requires elevated privileges, so in most cases this code needs to be run
|
||||||
|
// as root.
|
||||||
|
package netns
|
|
@ -1,33 +1,31 @@
|
||||||
// +build linux,go1.10
|
|
||||||
|
|
||||||
package netns
|
package netns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Deprecated: use syscall pkg instead (go >= 1.5 needed).
|
// Deprecated: use golang.org/x/sys/unix pkg instead.
|
||||||
const (
|
const (
|
||||||
CLONE_NEWUTS = 0x04000000 /* New utsname group? */
|
CLONE_NEWUTS = unix.CLONE_NEWUTS /* New utsname group? */
|
||||||
CLONE_NEWIPC = 0x08000000 /* New ipcs */
|
CLONE_NEWIPC = unix.CLONE_NEWIPC /* New ipcs */
|
||||||
CLONE_NEWUSER = 0x10000000 /* New user namespace */
|
CLONE_NEWUSER = unix.CLONE_NEWUSER /* New user namespace */
|
||||||
CLONE_NEWPID = 0x20000000 /* New pid namespace */
|
CLONE_NEWPID = unix.CLONE_NEWPID /* New pid namespace */
|
||||||
CLONE_NEWNET = 0x40000000 /* New network namespace */
|
CLONE_NEWNET = unix.CLONE_NEWNET /* New network namespace */
|
||||||
CLONE_IO = 0x80000000 /* Get io context */
|
CLONE_IO = unix.CLONE_IO /* Get io context */
|
||||||
bindMountPath = "/run/netns" /* Bind mount path for named netns */
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Setns sets namespace using syscall. Note that this should be a method
|
const bindMountPath = "/run/netns" /* Bind mount path for named netns */
|
||||||
// in syscall but it has not been added.
|
|
||||||
|
// Setns sets namespace using golang.org/x/sys/unix.Setns.
|
||||||
|
//
|
||||||
|
// Deprecated: Use golang.org/x/sys/unix.Setns instead.
|
||||||
func Setns(ns NsHandle, nstype int) (err error) {
|
func Setns(ns NsHandle, nstype int) (err error) {
|
||||||
return unix.Setns(int(ns), nstype)
|
return unix.Setns(int(ns), nstype)
|
||||||
}
|
}
|
||||||
|
@ -35,19 +33,20 @@ func Setns(ns NsHandle, nstype int) (err error) {
|
||||||
// Set sets the current network namespace to the namespace represented
|
// Set sets the current network namespace to the namespace represented
|
||||||
// by NsHandle.
|
// by NsHandle.
|
||||||
func Set(ns NsHandle) (err error) {
|
func Set(ns NsHandle) (err error) {
|
||||||
return Setns(ns, CLONE_NEWNET)
|
return unix.Setns(int(ns), unix.CLONE_NEWNET)
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new network namespace, sets it as current and returns
|
// New creates a new network namespace, sets it as current and returns
|
||||||
// a handle to it.
|
// a handle to it.
|
||||||
func New() (ns NsHandle, err error) {
|
func New() (ns NsHandle, err error) {
|
||||||
if err := unix.Unshare(CLONE_NEWNET); err != nil {
|
if err := unix.Unshare(unix.CLONE_NEWNET); err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
return Get()
|
return Get()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewNamed creates a new named network namespace and returns a handle to it
|
// NewNamed creates a new named network namespace, sets it as current,
|
||||||
|
// and returns a handle to it
|
||||||
func NewNamed(name string) (NsHandle, error) {
|
func NewNamed(name string) (NsHandle, error) {
|
||||||
if _, err := os.Stat(bindMountPath); os.IsNotExist(err) {
|
if _, err := os.Stat(bindMountPath); os.IsNotExist(err) {
|
||||||
err = os.MkdirAll(bindMountPath, 0755)
|
err = os.MkdirAll(bindMountPath, 0755)
|
||||||
|
@ -65,13 +64,15 @@ func NewNamed(name string) (NsHandle, error) {
|
||||||
|
|
||||||
f, err := os.OpenFile(namedPath, os.O_CREATE|os.O_EXCL, 0444)
|
f, err := os.OpenFile(namedPath, os.O_CREATE|os.O_EXCL, 0444)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
newNs.Close()
|
||||||
return None(), err
|
return None(), err
|
||||||
}
|
}
|
||||||
f.Close()
|
f.Close()
|
||||||
|
|
||||||
nsPath := fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), syscall.Gettid())
|
nsPath := fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), unix.Gettid())
|
||||||
err = syscall.Mount(nsPath, namedPath, "bind", syscall.MS_BIND, "")
|
err = unix.Mount(nsPath, namedPath, "bind", unix.MS_BIND, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
newNs.Close()
|
||||||
return None(), err
|
return None(), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +83,7 @@ func NewNamed(name string) (NsHandle, error) {
|
||||||
func DeleteNamed(name string) error {
|
func DeleteNamed(name string) error {
|
||||||
namedPath := path.Join(bindMountPath, name)
|
namedPath := path.Join(bindMountPath, name)
|
||||||
|
|
||||||
err := syscall.Unmount(namedPath, syscall.MNT_DETACH)
|
err := unix.Unmount(namedPath, unix.MNT_DETACH)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -108,7 +109,7 @@ func GetFromPath(path string) (NsHandle, error) {
|
||||||
// GetFromName gets a handle to a named network namespace such as one
|
// GetFromName gets a handle to a named network namespace such as one
|
||||||
// created by `ip netns add`.
|
// created by `ip netns add`.
|
||||||
func GetFromName(name string) (NsHandle, error) {
|
func GetFromName(name string) (NsHandle, error) {
|
||||||
return GetFromPath(fmt.Sprintf("/var/run/netns/%s", name))
|
return GetFromPath(filepath.Join(bindMountPath, name))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFromPid gets a handle to the network namespace of a given pid.
|
// GetFromPid gets a handle to the network namespace of a given pid.
|
||||||
|
@ -133,33 +134,38 @@ func GetFromDocker(id string) (NsHandle, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// borrowed from docker/utils/utils.go
|
// borrowed from docker/utils/utils.go
|
||||||
func findCgroupMountpoint(cgroupType string) (string, error) {
|
func findCgroupMountpoint(cgroupType string) (int, string, error) {
|
||||||
output, err := ioutil.ReadFile("/proc/mounts")
|
output, err := os.ReadFile("/proc/mounts")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return -1, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// /proc/mounts has 6 fields per line, one mount per line, e.g.
|
// /proc/mounts has 6 fields per line, one mount per line, e.g.
|
||||||
// cgroup /sys/fs/cgroup/devices cgroup rw,relatime,devices 0 0
|
// cgroup /sys/fs/cgroup/devices cgroup rw,relatime,devices 0 0
|
||||||
for _, line := range strings.Split(string(output), "\n") {
|
for _, line := range strings.Split(string(output), "\n") {
|
||||||
parts := strings.Split(line, " ")
|
parts := strings.Split(line, " ")
|
||||||
if len(parts) == 6 && parts[2] == "cgroup" {
|
if len(parts) == 6 {
|
||||||
for _, opt := range strings.Split(parts[3], ",") {
|
switch parts[2] {
|
||||||
if opt == cgroupType {
|
case "cgroup2":
|
||||||
return parts[1], nil
|
return 2, parts[1], nil
|
||||||
|
case "cgroup":
|
||||||
|
for _, opt := range strings.Split(parts[3], ",") {
|
||||||
|
if opt == cgroupType {
|
||||||
|
return 1, parts[1], nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", fmt.Errorf("cgroup mountpoint not found for %s", cgroupType)
|
return -1, "", fmt.Errorf("cgroup mountpoint not found for %s", cgroupType)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the relative path to the cgroup docker is running in.
|
// Returns the relative path to the cgroup docker is running in.
|
||||||
// borrowed from docker/utils/utils.go
|
// borrowed from docker/utils/utils.go
|
||||||
// modified to get the docker pid instead of using /proc/self
|
// modified to get the docker pid instead of using /proc/self
|
||||||
func getThisCgroup(cgroupType string) (string, error) {
|
func getDockerCgroup(cgroupVer int, cgroupType string) (string, error) {
|
||||||
dockerpid, err := ioutil.ReadFile("/var/run/docker.pid")
|
dockerpid, err := os.ReadFile("/var/run/docker.pid")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -171,14 +177,15 @@ func getThisCgroup(cgroupType string) (string, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
output, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/cgroup", pid))
|
output, err := os.ReadFile(fmt.Sprintf("/proc/%d/cgroup", pid))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
for _, line := range strings.Split(string(output), "\n") {
|
for _, line := range strings.Split(string(output), "\n") {
|
||||||
parts := strings.Split(line, ":")
|
parts := strings.Split(line, ":")
|
||||||
// any type used by docker should work
|
// any type used by docker should work
|
||||||
if parts[1] == cgroupType {
|
if (cgroupVer == 1 && parts[1] == cgroupType) ||
|
||||||
|
(cgroupVer == 2 && parts[1] == "") {
|
||||||
return parts[2], nil
|
return parts[2], nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,46 +197,56 @@ func getThisCgroup(cgroupType string) (string, error) {
|
||||||
// modified to only return the first pid
|
// modified to only return the first pid
|
||||||
// modified to glob with id
|
// modified to glob with id
|
||||||
// modified to search for newer docker containers
|
// modified to search for newer docker containers
|
||||||
|
// modified to look for cgroups v2
|
||||||
func getPidForContainer(id string) (int, error) {
|
func getPidForContainer(id string) (int, error) {
|
||||||
pid := 0
|
pid := 0
|
||||||
|
|
||||||
// memory is chosen randomly, any cgroup used by docker works
|
// memory is chosen randomly, any cgroup used by docker works
|
||||||
cgroupType := "memory"
|
cgroupType := "memory"
|
||||||
|
|
||||||
cgroupRoot, err := findCgroupMountpoint(cgroupType)
|
cgroupVer, cgroupRoot, err := findCgroupMountpoint(cgroupType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return pid, err
|
return pid, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cgroupThis, err := getThisCgroup(cgroupType)
|
cgroupDocker, err := getDockerCgroup(cgroupVer, cgroupType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return pid, err
|
return pid, err
|
||||||
}
|
}
|
||||||
|
|
||||||
id += "*"
|
id += "*"
|
||||||
|
|
||||||
|
var pidFile string
|
||||||
|
if cgroupVer == 1 {
|
||||||
|
pidFile = "tasks"
|
||||||
|
} else if cgroupVer == 2 {
|
||||||
|
pidFile = "cgroup.procs"
|
||||||
|
} else {
|
||||||
|
return -1, fmt.Errorf("Invalid cgroup version '%d'", cgroupVer)
|
||||||
|
}
|
||||||
|
|
||||||
attempts := []string{
|
attempts := []string{
|
||||||
filepath.Join(cgroupRoot, cgroupThis, id, "tasks"),
|
filepath.Join(cgroupRoot, cgroupDocker, id, pidFile),
|
||||||
// With more recent lxc versions use, cgroup will be in lxc/
|
// With more recent lxc versions use, cgroup will be in lxc/
|
||||||
filepath.Join(cgroupRoot, cgroupThis, "lxc", id, "tasks"),
|
filepath.Join(cgroupRoot, cgroupDocker, "lxc", id, pidFile),
|
||||||
// With more recent docker, cgroup will be in docker/
|
// With more recent docker, cgroup will be in docker/
|
||||||
filepath.Join(cgroupRoot, cgroupThis, "docker", id, "tasks"),
|
filepath.Join(cgroupRoot, cgroupDocker, "docker", id, pidFile),
|
||||||
// Even more recent docker versions under systemd use docker-<id>.scope/
|
// Even more recent docker versions under systemd use docker-<id>.scope/
|
||||||
filepath.Join(cgroupRoot, "system.slice", "docker-"+id+".scope", "tasks"),
|
filepath.Join(cgroupRoot, "system.slice", "docker-"+id+".scope", pidFile),
|
||||||
// Even more recent docker versions under cgroup/systemd/docker/<id>/
|
// Even more recent docker versions under cgroup/systemd/docker/<id>/
|
||||||
filepath.Join(cgroupRoot, "..", "systemd", "docker", id, "tasks"),
|
filepath.Join(cgroupRoot, "..", "systemd", "docker", id, pidFile),
|
||||||
// Kubernetes with docker and CNI is even more different. Works for BestEffort and Burstable QoS
|
// Kubernetes with docker and CNI is even more different. Works for BestEffort and Burstable QoS
|
||||||
filepath.Join(cgroupRoot, "..", "systemd", "kubepods", "*", "pod*", id, "tasks"),
|
filepath.Join(cgroupRoot, "..", "systemd", "kubepods", "*", "pod*", id, pidFile),
|
||||||
// Same as above but for Guaranteed QoS
|
// Same as above but for Guaranteed QoS
|
||||||
filepath.Join(cgroupRoot, "..", "systemd", "kubepods", "pod*", id, "tasks"),
|
filepath.Join(cgroupRoot, "..", "systemd", "kubepods", "pod*", id, pidFile),
|
||||||
// Another flavor of containers location in recent kubernetes 1.11+. Works for BestEffort and Burstable QoS
|
// Another flavor of containers location in recent kubernetes 1.11+. Works for BestEffort and Burstable QoS
|
||||||
filepath.Join(cgroupRoot, cgroupThis, "kubepods.slice", "*.slice", "*", "docker-"+id+".scope", "tasks"),
|
filepath.Join(cgroupRoot, cgroupDocker, "kubepods.slice", "*.slice", "*", "docker-"+id+".scope", pidFile),
|
||||||
// Same as above but for Guaranteed QoS
|
// Same as above but for Guaranteed QoS
|
||||||
filepath.Join(cgroupRoot, cgroupThis, "kubepods.slice", "*", "docker-"+id+".scope", "tasks"),
|
filepath.Join(cgroupRoot, cgroupDocker, "kubepods.slice", "*", "docker-"+id+".scope", pidFile),
|
||||||
// When runs inside of a container with recent kubernetes 1.11+. Works for BestEffort and Burstable QoS
|
// When runs inside of a container with recent kubernetes 1.11+. Works for BestEffort and Burstable QoS
|
||||||
filepath.Join(cgroupRoot, "kubepods.slice", "*.slice", "*", "docker-"+id+".scope", "tasks"),
|
filepath.Join(cgroupRoot, "kubepods.slice", "*.slice", "*", "docker-"+id+".scope", pidFile),
|
||||||
// Same as above but for Guaranteed QoS
|
// Same as above but for Guaranteed QoS
|
||||||
filepath.Join(cgroupRoot, "kubepods.slice", "*", "docker-"+id+".scope", "tasks"),
|
filepath.Join(cgroupRoot, "kubepods.slice", "*", "docker-"+id+".scope", pidFile),
|
||||||
}
|
}
|
||||||
|
|
||||||
var filename string
|
var filename string
|
||||||
|
@ -247,7 +264,7 @@ func getPidForContainer(id string) (int, error) {
|
||||||
return pid, fmt.Errorf("Unable to find container: %v", id[:len(id)-1])
|
return pid, fmt.Errorf("Unable to find container: %v", id[:len(id)-1])
|
||||||
}
|
}
|
||||||
|
|
||||||
output, err := ioutil.ReadFile(filename)
|
output, err := os.ReadFile(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return pid, err
|
return pid, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
//go:build !linux
|
||||||
// +build !linux
|
// +build !linux
|
||||||
|
|
||||||
package netns
|
package netns
|
||||||
|
@ -10,6 +11,14 @@ var (
|
||||||
ErrNotImplemented = errors.New("not implemented")
|
ErrNotImplemented = errors.New("not implemented")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Setns sets namespace using golang.org/x/sys/unix.Setns on Linux. It
|
||||||
|
// is not implemented on other platforms.
|
||||||
|
//
|
||||||
|
// Deprecated: Use golang.org/x/sys/unix.Setns instead.
|
||||||
|
func Setns(ns NsHandle, nstype int) (err error) {
|
||||||
|
return ErrNotImplemented
|
||||||
|
}
|
||||||
|
|
||||||
func Set(ns NsHandle) (err error) {
|
func Set(ns NsHandle) (err error) {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
@ -18,6 +27,14 @@ func New() (ns NsHandle, err error) {
|
||||||
return -1, ErrNotImplemented
|
return -1, ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewNamed(name string) (NsHandle, error) {
|
||||||
|
return -1, ErrNotImplemented
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteNamed(name string) error {
|
||||||
|
return ErrNotImplemented
|
||||||
|
}
|
||||||
|
|
||||||
func Get() (NsHandle, error) {
|
func Get() (NsHandle, error) {
|
||||||
return -1, ErrNotImplemented
|
return -1, ErrNotImplemented
|
||||||
}
|
}
|
|
@ -1,11 +1,3 @@
|
||||||
// Package netns allows ultra-simple network namespace handling. NsHandles
|
|
||||||
// can be retrieved and set. Note that the current namespace is thread
|
|
||||||
// local so actions that set and reset namespaces should use LockOSThread
|
|
||||||
// to make sure the namespace doesn't change due to a goroutine switch.
|
|
||||||
// It is best to close NsHandles when you are done with them. This can be
|
|
||||||
// accomplished via a `defer ns.Close()` on the handle. Changing namespaces
|
|
||||||
// requires elevated privileges, so in most cases this code needs to be run
|
|
||||||
// as root.
|
|
||||||
package netns
|
package netns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -38,7 +30,7 @@ func (ns NsHandle) Equal(other NsHandle) bool {
|
||||||
// String shows the file descriptor number and its dev and inode.
|
// String shows the file descriptor number and its dev and inode.
|
||||||
func (ns NsHandle) String() string {
|
func (ns NsHandle) String() string {
|
||||||
if ns == -1 {
|
if ns == -1 {
|
||||||
return "NS(None)"
|
return "NS(none)"
|
||||||
}
|
}
|
||||||
var s unix.Stat_t
|
var s unix.Stat_t
|
||||||
if err := unix.Fstat(int(ns), &s); err != nil {
|
if err := unix.Fstat(int(ns), &s); err != nil {
|
||||||
|
@ -71,7 +63,7 @@ func (ns *NsHandle) Close() error {
|
||||||
if err := unix.Close(int(*ns)); err != nil {
|
if err := unix.Close(int(*ns)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
(*ns) = -1
|
*ns = -1
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
//go:build !linux
|
||||||
|
// +build !linux
|
||||||
|
|
||||||
|
package netns
|
||||||
|
|
||||||
|
// NsHandle is a handle to a network namespace. It can only be used on Linux,
|
||||||
|
// but provides stub methods on other platforms.
|
||||||
|
type NsHandle int
|
||||||
|
|
||||||
|
// Equal determines if two network handles refer to the same network
|
||||||
|
// namespace. It is only implemented on Linux.
|
||||||
|
func (ns NsHandle) Equal(_ NsHandle) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// String shows the file descriptor number and its dev and inode.
|
||||||
|
// It is only implemented on Linux, and returns "NS(none)" on other
|
||||||
|
// platforms.
|
||||||
|
func (ns NsHandle) String() string {
|
||||||
|
return "NS(none)"
|
||||||
|
}
|
||||||
|
|
||||||
|
// UniqueId returns a string which uniquely identifies the namespace
|
||||||
|
// associated with the network handle. It is only implemented on Linux,
|
||||||
|
// and returns "NS(none)" on other platforms.
|
||||||
|
func (ns NsHandle) UniqueId() string {
|
||||||
|
return "NS(none)"
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsOpen returns true if Close() has not been called. It is only implemented
|
||||||
|
// on Linux and always returns false on other platforms.
|
||||||
|
func (ns NsHandle) IsOpen() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes the NsHandle and resets its file descriptor to -1.
|
||||||
|
// It is only implemented on Linux.
|
||||||
|
func (ns *NsHandle) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// None gets an empty (closed) NsHandle.
|
||||||
|
func None() NsHandle {
|
||||||
|
return NsHandle(-1)
|
||||||
|
}
|
|
@ -99,8 +99,8 @@ github.com/containernetworking/cni/pkg/types/create
|
||||||
github.com/containernetworking/cni/pkg/types/internal
|
github.com/containernetworking/cni/pkg/types/internal
|
||||||
github.com/containernetworking/cni/pkg/utils
|
github.com/containernetworking/cni/pkg/utils
|
||||||
github.com/containernetworking/cni/pkg/version
|
github.com/containernetworking/cni/pkg/version
|
||||||
# github.com/containernetworking/plugins v1.2.0
|
# github.com/containernetworking/plugins v1.3.0
|
||||||
## explicit; go 1.17
|
## explicit; go 1.20
|
||||||
github.com/containernetworking/plugins/pkg/ns
|
github.com/containernetworking/plugins/pkg/ns
|
||||||
# github.com/containers/buildah v1.30.1-0.20230504052500-e925b5852e07
|
# github.com/containers/buildah v1.30.1-0.20230504052500-e925b5852e07
|
||||||
## explicit; go 1.18
|
## explicit; go 1.18
|
||||||
|
@ -558,8 +558,8 @@ github.com/google/go-intervals/intervalset
|
||||||
## explicit; go 1.12
|
## explicit; go 1.12
|
||||||
github.com/google/gofuzz
|
github.com/google/gofuzz
|
||||||
github.com/google/gofuzz/bytesource
|
github.com/google/gofuzz/bytesource
|
||||||
# github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38
|
# github.com/google/pprof v0.0.0-20230323073829-e72429f035bd
|
||||||
## explicit; go 1.14
|
## explicit; go 1.19
|
||||||
github.com/google/pprof/profile
|
github.com/google/pprof/profile
|
||||||
# github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
# github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||||
## explicit; go 1.13
|
## explicit; go 1.13
|
||||||
|
@ -905,8 +905,8 @@ github.com/vbauerster/mpb/v8/internal
|
||||||
## explicit; go 1.12
|
## explicit; go 1.12
|
||||||
github.com/vishvananda/netlink
|
github.com/vishvananda/netlink
|
||||||
github.com/vishvananda/netlink/nl
|
github.com/vishvananda/netlink/nl
|
||||||
# github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f
|
# github.com/vishvananda/netns v0.0.4
|
||||||
## explicit; go 1.12
|
## explicit; go 1.17
|
||||||
github.com/vishvananda/netns
|
github.com/vishvananda/netns
|
||||||
# go.etcd.io/bbolt v1.3.7
|
# go.etcd.io/bbolt v1.3.7
|
||||||
## explicit; go 1.17
|
## explicit; go 1.17
|
||||||
|
|
Loading…
Reference in New Issue