1
2
3 package cpu
4
5 import (
6 "context"
7 "fmt"
8 "strings"
9 "unsafe"
10
11 "github.com/yusufpapurcu/wmi"
12 "github.com/shirou/gopsutil/internal/common"
13 "golang.org/x/sys/windows"
14 )
15
16 var (
17 procGetActiveProcessorCount = common.Modkernel32.NewProc("GetActiveProcessorCount")
18 procGetNativeSystemInfo = common.Modkernel32.NewProc("GetNativeSystemInfo")
19 )
20
21 type Win32_Processor struct {
22 Win32_ProcessorWithoutLoadPct
23 LoadPercentage *uint16
24 }
25
26
27
28
29 type Win32_ProcessorWithoutLoadPct struct {
30 Family uint16
31 Manufacturer string
32 Name string
33 NumberOfLogicalProcessors uint32
34 NumberOfCores uint32
35 ProcessorID *string
36 Stepping *string
37 MaxClockSpeed uint32
38 }
39
40
41
42
43
44
45 type win32_SystemProcessorPerformanceInformation struct {
46 IdleTime int64
47 KernelTime int64
48 UserTime int64
49 DpcTime int64
50 InterruptTime int64
51 InterruptCount uint32
52 }
53
54
55 type Win32_PerfFormattedData_PerfOS_System struct {
56 Processes uint32
57 ProcessorQueueLength uint32
58 }
59
60 const (
61 ClocksPerSec = 10000000.0
62
63
64
65 win32_SystemProcessorPerformanceInformationClass = 8
66
67
68 win32_SystemProcessorPerformanceInfoSize = uint32(unsafe.Sizeof(win32_SystemProcessorPerformanceInformation{}))
69 )
70
71
72 func Times(percpu bool) ([]TimesStat, error) {
73 return TimesWithContext(context.Background(), percpu)
74 }
75
76 func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
77 if percpu {
78 return perCPUTimes()
79 }
80
81 var ret []TimesStat
82 var lpIdleTime common.FILETIME
83 var lpKernelTime common.FILETIME
84 var lpUserTime common.FILETIME
85 r, _, _ := common.ProcGetSystemTimes.Call(
86 uintptr(unsafe.Pointer(&lpIdleTime)),
87 uintptr(unsafe.Pointer(&lpKernelTime)),
88 uintptr(unsafe.Pointer(&lpUserTime)))
89 if r == 0 {
90 return ret, windows.GetLastError()
91 }
92
93 LOT := float64(0.0000001)
94 HIT := (LOT * 4294967296.0)
95 idle := ((HIT * float64(lpIdleTime.DwHighDateTime)) + (LOT * float64(lpIdleTime.DwLowDateTime)))
96 user := ((HIT * float64(lpUserTime.DwHighDateTime)) + (LOT * float64(lpUserTime.DwLowDateTime)))
97 kernel := ((HIT * float64(lpKernelTime.DwHighDateTime)) + (LOT * float64(lpKernelTime.DwLowDateTime)))
98 system := (kernel - idle)
99
100 ret = append(ret, TimesStat{
101 CPU: "cpu-total",
102 Idle: float64(idle),
103 User: float64(user),
104 System: float64(system),
105 })
106 return ret, nil
107 }
108
109 func Info() ([]InfoStat, error) {
110 return InfoWithContext(context.Background())
111 }
112
113 func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
114 var ret []InfoStat
115 var dst []Win32_ProcessorWithoutLoadPct
116 q := wmi.CreateQuery(&dst, "")
117 q = strings.ReplaceAll(q, "Win32_ProcessorWithoutLoadPct", "Win32_Processor")
118 if err := common.WMIQueryWithContext(ctx, q, &dst); err != nil {
119 return ret, err
120 }
121
122 var procID string
123 for i, l := range dst {
124 procID = ""
125 if l.ProcessorID != nil {
126 procID = *l.ProcessorID
127 }
128
129 cpu := InfoStat{
130 CPU: int32(i),
131 Family: fmt.Sprintf("%d", l.Family),
132 VendorID: l.Manufacturer,
133 ModelName: l.Name,
134 Cores: int32(l.NumberOfLogicalProcessors),
135 PhysicalID: procID,
136 Mhz: float64(l.MaxClockSpeed),
137 Flags: []string{},
138 }
139 ret = append(ret, cpu)
140 }
141
142 return ret, nil
143 }
144
145
146
147 func ProcInfo() ([]Win32_PerfFormattedData_PerfOS_System, error) {
148 return ProcInfoWithContext(context.Background())
149 }
150
151 func ProcInfoWithContext(ctx context.Context) ([]Win32_PerfFormattedData_PerfOS_System, error) {
152 var ret []Win32_PerfFormattedData_PerfOS_System
153 q := wmi.CreateQuery(&ret, "")
154 err := common.WMIQueryWithContext(ctx, q, &ret)
155 if err != nil {
156 return []Win32_PerfFormattedData_PerfOS_System{}, err
157 }
158 return ret, err
159 }
160
161
162 func perCPUTimes() ([]TimesStat, error) {
163 var ret []TimesStat
164 stats, err := perfInfo()
165 if err != nil {
166 return nil, err
167 }
168 for core, v := range stats {
169 c := TimesStat{
170 CPU: fmt.Sprintf("cpu%d", core),
171 User: float64(v.UserTime) / ClocksPerSec,
172 System: float64(v.KernelTime-v.IdleTime) / ClocksPerSec,
173 Idle: float64(v.IdleTime) / ClocksPerSec,
174 Irq: float64(v.InterruptTime) / ClocksPerSec,
175 }
176 ret = append(ret, c)
177 }
178 return ret, nil
179 }
180
181
182 func perfInfo() ([]win32_SystemProcessorPerformanceInformation, error) {
183
184
185
186 maxBuffer := 2056
187
188 resultBuffer := make([]win32_SystemProcessorPerformanceInformation, maxBuffer)
189
190 bufferSize := uintptr(win32_SystemProcessorPerformanceInfoSize) * uintptr(maxBuffer)
191
192 var retSize uint32
193
194
195
196
197 retCode, _, err := common.ProcNtQuerySystemInformation.Call(
198 win32_SystemProcessorPerformanceInformationClass,
199 uintptr(unsafe.Pointer(&resultBuffer[0])),
200 bufferSize,
201 uintptr(unsafe.Pointer(&retSize)),
202 )
203
204
205 if retCode != 0 {
206 return nil, fmt.Errorf("call to NtQuerySystemInformation returned %d. err: %s", retCode, err.Error())
207 }
208
209
210 numReturnedElements := retSize / win32_SystemProcessorPerformanceInfoSize
211
212
213 resultBuffer = resultBuffer[:numReturnedElements]
214
215 return resultBuffer, nil
216 }
217
218
219
220
221 type systemInfo struct {
222 wProcessorArchitecture uint16
223 wReserved uint16
224 dwPageSize uint32
225 lpMinimumApplicationAddress uintptr
226 lpMaximumApplicationAddress uintptr
227 dwActiveProcessorMask uintptr
228 dwNumberOfProcessors uint32
229 dwProcessorType uint32
230 dwAllocationGranularity uint32
231 wProcessorLevel uint16
232 wProcessorRevision uint16
233 }
234
235 func CountsWithContext(ctx context.Context, logical bool) (int, error) {
236 if logical {
237
238 err := procGetActiveProcessorCount.Find()
239 if err == nil {
240 ret, _, _ := procGetActiveProcessorCount.Call(uintptr(0xffff))
241 if ret != 0 {
242 return int(ret), nil
243 }
244 }
245 var systemInfo systemInfo
246 _, _, err = procGetNativeSystemInfo.Call(uintptr(unsafe.Pointer(&systemInfo)))
247 if systemInfo.dwNumberOfProcessors == 0 {
248 return 0, err
249 }
250 return int(systemInfo.dwNumberOfProcessors), nil
251 }
252
253
254 var dst []Win32_ProcessorWithoutLoadPct
255 q := wmi.CreateQuery(&dst, "")
256 q = strings.ReplaceAll(q, "Win32_ProcessorWithoutLoadPct", "Win32_Processor")
257 if err := common.WMIQueryWithContext(ctx, q, &dst); err != nil {
258 return 0, err
259 }
260 var count uint32
261 for _, d := range dst {
262 count += d.NumberOfCores
263 }
264 return int(count), nil
265 }
266
View as plain text