package daemon // import "github.com/docker/docker/daemon" import ( "context" "errors" "fmt" "time" containertypes "github.com/docker/docker/api/types/container" libcontainerdtypes "github.com/docker/docker/libcontainerd/types" units "github.com/docker/go-units" ) // ContainerTop handles `docker top` client requests. // // Future considerations: // - Windows users are far more familiar with CPU% total. // Further, users on Windows rarely see user/kernel CPU stats split. // The kernel returns everything in terms of 100ns. To obtain // CPU%, we could do something like docker stats does which takes two // samples, subtract the difference and do the maths. Unfortunately this // would slow the stat call down and require two kernel calls. So instead, // we do something similar to linux and display the CPU as combined HH:MM:SS.mmm. // - Perhaps we could add an argument to display "raw" stats // - "Memory" is an extremely overloaded term in Windows. Hence we do what // task manager does and use the private working set as the memory counter. // We could return more info for those who really understand how memory // management works in Windows if we introduced a "raw" stats (above). func (daemon *Daemon) ContainerTop(name string, psArgs string) (*containertypes.ContainerTopOKBody, error) { // It's not at all an equivalent to linux 'ps' on Windows if psArgs != "" { return nil, errors.New("Windows does not support arguments to top") } container, err := daemon.GetContainer(name) if err != nil { return nil, err } task, err := func() (libcontainerdtypes.Task, error) { container.Lock() defer container.Unlock() task, err := container.GetRunningTask() if err != nil { return nil, err } if container.Restarting { return nil, errContainerIsRestarting(container.ID) } return task, nil }() s, err := task.Summary(context.Background()) if err != nil { return nil, err } procList := &containertypes.ContainerTopOKBody{} procList.Titles = []string{"Name", "PID", "CPU", "Private Working Set"} for _, j := range s { d := time.Duration((j.KernelTime_100Ns + j.UserTime_100Ns) * 100) // Combined time in nanoseconds procList.Processes = append(procList.Processes, []string{ j.ImageName, fmt.Sprint(j.ProcessID), fmt.Sprintf("%02d:%02d:%02d.%03d", int(d.Hours()), int(d.Minutes())%60, int(d.Seconds())%60, int(d.Nanoseconds()/1000000)%1000), units.HumanSize(float64(j.MemoryWorkingSetPrivateBytes)), }) } return procList, nil }