1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Merge pull request #37131 from kolyshkin/top-opt

Optimize ContainerTop() aka docker top
This commit is contained in:
Sebastiaan van Stijn 2018-05-30 03:28:07 +02:00 committed by GitHub
commit 65bd038fc5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 46 additions and 2 deletions

View file

@ -229,6 +229,10 @@ func checkMounted(t *testing.T, p string, expect bool) {
} }
func TestRootMountCleanup(t *testing.T) { func TestRootMountCleanup(t *testing.T) {
if os.Getuid() != 0 {
t.Skip("root required")
}
t.Parallel() t.Parallel()
testRoot, err := ioutil.TempDir("", t.Name()) testRoot, err := ioutil.TempDir("", t.Name())

View file

@ -153,6 +153,10 @@ func TestValidContainerNames(t *testing.T) {
} }
func TestContainerInitDNS(t *testing.T) { func TestContainerInitDNS(t *testing.T) {
if os.Getuid() != 0 {
t.Skip("root required") // for chown
}
tmp, err := ioutil.TempDir("", "docker-container-test-") tmp, err := ioutil.TempDir("", "docker-container-test-")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)

View file

@ -1,6 +1,7 @@
package daemon // import "github.com/docker/docker/daemon" package daemon // import "github.com/docker/docker/daemon"
import ( import (
"os"
"reflect" "reflect"
"sort" "sort"
"testing" "testing"
@ -499,6 +500,9 @@ func TestDaemonDiscoveryReloadOnlyClusterAdvertise(t *testing.T) {
} }
func TestDaemonReloadNetworkDiagnosticPort(t *testing.T) { func TestDaemonReloadNetworkDiagnosticPort(t *testing.T) {
if os.Getuid() != 0 {
t.Skip("root required")
}
daemon := &Daemon{ daemon := &Daemon{
imageService: images.NewImageService(images.ImageServiceConfig{}), imageService: images.NewImageService(images.ImageServiceConfig{}),
} }

View file

@ -3,6 +3,7 @@
package daemon // import "github.com/docker/docker/daemon" package daemon // import "github.com/docker/docker/daemon"
import ( import (
"bytes"
"context" "context"
"fmt" "fmt"
"os/exec" "os/exec"
@ -11,6 +12,8 @@ import (
"strings" "strings"
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
"github.com/docker/docker/errdefs"
"github.com/pkg/errors"
) )
func validatePSArgs(psArgs string) error { func validatePSArgs(psArgs string) error {
@ -70,6 +73,7 @@ func parsePSOutput(output []byte, procs []uint32) (*container.ContainerTopOKBody
for i, name := range procList.Titles { for i, name := range procList.Titles {
if name == "PID" { if name == "PID" {
pidIndex = i pidIndex = i
break
} }
} }
if pidIndex == -1 { if pidIndex == -1 {
@ -112,6 +116,20 @@ func parsePSOutput(output []byte, procs []uint32) (*container.ContainerTopOKBody
return procList, nil return procList, nil
} }
// psPidsArg converts a slice of PIDs to a string consisting
// of comma-separated list of PIDs prepended by "-q".
// For example, psPidsArg([]uint32{1,2,3}) returns "-q1,2,3".
func psPidsArg(pids []uint32) string {
b := []byte{'-', 'q'}
for i, p := range pids {
b = strconv.AppendUint(b, uint64(p), 10)
if i < len(pids)-1 {
b = append(b, ',')
}
}
return string(b)
}
// ContainerTop lists the processes running inside of the given // ContainerTop lists the processes running inside of the given
// container by calling ps with the given args, or with the flags // container by calling ps with the given args, or with the flags
// "-ef" if no args are given. An error is returned if the container // "-ef" if no args are given. An error is returned if the container
@ -144,9 +162,23 @@ func (daemon *Daemon) ContainerTop(name string, psArgs string) (*container.Conta
return nil, err return nil, err
} }
output, err := exec.Command("ps", strings.Split(psArgs, " ")...).Output() args := strings.Split(psArgs, " ")
pids := psPidsArg(procs)
output, err := exec.Command("ps", append(args, pids)...).Output()
if err != nil { if err != nil {
return nil, fmt.Errorf("Error running ps: %v", err) // some ps options (such as f) can't be used together with q,
// so retry without it
output, err = exec.Command("ps", args...).Output()
if err != nil {
if ee, ok := err.(*exec.ExitError); ok {
// first line of stderr shows why ps failed
line := bytes.SplitN(ee.Stderr, []byte{'\n'}, 2)
if len(line) > 0 && len(line[0]) > 0 {
err = errors.New(string(line[0]))
}
}
return nil, errdefs.System(errors.Wrap(err, "ps"))
}
} }
procList, err := parsePSOutput(output, procs) procList, err := parsePSOutput(output, procs)
if err != nil { if err != nil {