top_windows.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. package daemon // import "github.com/docker/docker/daemon"
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "time"
  7. containertypes "github.com/docker/docker/api/types/container"
  8. libcontainerdtypes "github.com/docker/docker/libcontainerd/types"
  9. units "github.com/docker/go-units"
  10. )
  11. // ContainerTop handles `docker top` client requests.
  12. //
  13. // Future considerations:
  14. // - Windows users are far more familiar with CPU% total.
  15. // Further, users on Windows rarely see user/kernel CPU stats split.
  16. // The kernel returns everything in terms of 100ns. To obtain
  17. // CPU%, we could do something like docker stats does which takes two
  18. // samples, subtract the difference and do the maths. Unfortunately this
  19. // would slow the stat call down and require two kernel calls. So instead,
  20. // we do something similar to linux and display the CPU as combined HH:MM:SS.mmm.
  21. // - Perhaps we could add an argument to display "raw" stats
  22. // - "Memory" is an extremely overloaded term in Windows. Hence we do what
  23. // task manager does and use the private working set as the memory counter.
  24. // We could return more info for those who really understand how memory
  25. // management works in Windows if we introduced a "raw" stats (above).
  26. func (daemon *Daemon) ContainerTop(name string, psArgs string) (*containertypes.ContainerTopOKBody, error) {
  27. // It's not at all an equivalent to linux 'ps' on Windows
  28. if psArgs != "" {
  29. return nil, errors.New("Windows does not support arguments to top")
  30. }
  31. container, err := daemon.GetContainer(name)
  32. if err != nil {
  33. return nil, err
  34. }
  35. task, err := func() (libcontainerdtypes.Task, error) {
  36. container.Lock()
  37. defer container.Unlock()
  38. task, err := container.GetRunningTask()
  39. if err != nil {
  40. return nil, err
  41. }
  42. if container.Restarting {
  43. return nil, errContainerIsRestarting(container.ID)
  44. }
  45. return task, nil
  46. }()
  47. s, err := task.Summary(context.Background())
  48. if err != nil {
  49. return nil, err
  50. }
  51. procList := &containertypes.ContainerTopOKBody{}
  52. procList.Titles = []string{"Name", "PID", "CPU", "Private Working Set"}
  53. for _, j := range s {
  54. d := time.Duration((j.KernelTime_100Ns + j.UserTime_100Ns) * 100) // Combined time in nanoseconds
  55. procList.Processes = append(procList.Processes, []string{
  56. j.ImageName,
  57. fmt.Sprint(j.ProcessID),
  58. fmt.Sprintf("%02d:%02d:%02d.%03d", int(d.Hours()), int(d.Minutes())%60, int(d.Seconds())%60, int(d.Nanoseconds()/1000000)%1000),
  59. units.HumanSize(float64(j.MemoryWorkingSetPrivateBytes)),
  60. })
  61. }
  62. return procList, nil
  63. }