1
2
3 package uvm
4
5 import (
6 "context"
7 "strings"
8
9 "github.com/Microsoft/go-winio/pkg/guid"
10 "github.com/Microsoft/go-winio/pkg/process"
11 "github.com/pkg/errors"
12 "github.com/sirupsen/logrus"
13 "golang.org/x/sys/windows"
14
15 "github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/stats"
16 hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
17 "github.com/Microsoft/hcsshim/internal/log"
18 )
19
20
21
22
23
24
25 func checkProcess(ctx context.Context, pid uint32, desiredProcessName string, desiredDomain string, desiredUser string) (p windows.Handle, err error) {
26 desiredProcessName = strings.ToUpper(desiredProcessName)
27 desiredDomain = strings.ToUpper(desiredDomain)
28 desiredUser = strings.ToUpper(desiredUser)
29
30 p, err = windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION|windows.PROCESS_VM_READ, false, pid)
31 if err != nil {
32 return 0, err
33 }
34 defer func(openedProcess windows.Handle) {
35
36 if p == 0 {
37 windows.Close(openedProcess)
38 }
39 }(p)
40
41
42 name, err := process.QueryFullProcessImageName(p, process.ImageNameFormatNTPath)
43 if err != nil {
44 return 0, err
45 }
46 if strings.ToUpper(name) == desiredProcessName {
47 var t windows.Token
48 if err := windows.OpenProcessToken(p, windows.TOKEN_QUERY, &t); err != nil {
49 return 0, err
50 }
51 defer t.Close()
52 tUser, err := t.GetTokenUser()
53 if err != nil {
54 return 0, err
55 }
56 user, domain, _, err := tUser.User.Sid.LookupAccount("")
57 if err != nil {
58 return 0, err
59 }
60 log.G(ctx).WithFields(logrus.Fields{
61 "name": name,
62 "domain": domain,
63 "user": user,
64 }).Debug("checking vmmem process identity")
65 if strings.ToUpper(domain) == desiredDomain && strings.ToUpper(user) == desiredUser {
66 return p, nil
67 }
68 }
69 return 0, nil
70 }
71
72
73
74
75
76 func lookupVMMEM(ctx context.Context, vmID guid.GUID) (proc windows.Handle, err error) {
77 vmIDStr := strings.ToUpper(vmID.String())
78 log.G(ctx).WithField("vmID", vmIDStr).Debug("looking up vmmem")
79
80 pids, err := process.EnumProcesses()
81 if err != nil {
82 return 0, errors.Wrap(err, "failed to enumerate processes")
83 }
84 for _, pid := range pids {
85 p, err := checkProcess(ctx, pid, "vmmem", "NT VIRTUAL MACHINE", vmIDStr)
86 if err != nil {
87
88
89
90
91 log.G(ctx).WithField("pid", pid).Debug("failed to check process")
92 continue
93 }
94 if p != 0 {
95 log.G(ctx).WithField("pid", pid).Debug("found vmmem match")
96 return p, nil
97 }
98 }
99 return 0, errors.New("failed to find matching vmmem process")
100 }
101
102
103
104
105 func (uvm *UtilityVM) getVMMEMProcess(ctx context.Context) (windows.Handle, error) {
106 uvm.vmmemOnce.Do(func() {
107 uvm.vmmemProcess, uvm.vmmemErr = lookupVMMEM(ctx, uvm.runtimeID)
108 })
109 return uvm.vmmemProcess, uvm.vmmemErr
110 }
111
112
113 func (uvm *UtilityVM) Stats(ctx context.Context) (*stats.VirtualMachineStatistics, error) {
114 s := &stats.VirtualMachineStatistics{}
115 props, err := uvm.hcsSystem.PropertiesV2(ctx, hcsschema.PTStatistics, hcsschema.PTMemory)
116 if err != nil {
117 return nil, err
118 }
119 s.Processor = &stats.VirtualMachineProcessorStatistics{}
120 s.Processor.TotalRuntimeNS = uint64(props.Statistics.Processor.TotalRuntime100ns * 100)
121
122 s.Memory = &stats.VirtualMachineMemoryStatistics{}
123 if uvm.physicallyBacked {
124
125
126
127 if props.Memory != nil {
128 s.Memory.WorkingSetBytes = props.Memory.VirtualMachineMemory.AssignedMemory * 4096
129 }
130 } else {
131
132
133
134
135 vmmemProc, err := uvm.getVMMEMProcess(ctx)
136 if err != nil {
137 return nil, err
138 }
139 memCounters, err := process.GetProcessMemoryInfo(vmmemProc)
140 if err != nil {
141 return nil, err
142 }
143 s.Memory.WorkingSetBytes = uint64(memCounters.WorkingSetSize)
144 }
145
146 if props.Memory != nil {
147 s.Memory.VirtualNodeCount = props.Memory.VirtualNodeCount
148 s.Memory.VmMemory = &stats.VirtualMachineMemory{}
149 s.Memory.VmMemory.AvailableMemory = props.Memory.VirtualMachineMemory.AvailableMemory
150 s.Memory.VmMemory.AvailableMemoryBuffer = props.Memory.VirtualMachineMemory.AvailableMemoryBuffer
151 s.Memory.VmMemory.ReservedMemory = props.Memory.VirtualMachineMemory.ReservedMemory
152 s.Memory.VmMemory.AssignedMemory = props.Memory.VirtualMachineMemory.AssignedMemory
153 s.Memory.VmMemory.SlpActive = props.Memory.VirtualMachineMemory.SlpActive
154 s.Memory.VmMemory.BalancingEnabled = props.Memory.VirtualMachineMemory.BalancingEnabled
155 s.Memory.VmMemory.DmOperationInProgress = props.Memory.VirtualMachineMemory.DmOperationInProgress
156 }
157 return s, nil
158 }
159
View as plain text