@@ -5,12 +5,16 @@ package cpu
5
5
6
6
import (
7
7
"context"
8
+ "fmt"
8
9
"strconv"
9
10
"strings"
11
+ "unsafe"
10
12
11
13
"github.com/shoenig/go-m1cpu"
12
14
"github.com/tklauser/go-sysconf"
13
15
"golang.org/x/sys/unix"
16
+
17
+ "github.com/shirou/gopsutil/v4/internal/common"
14
18
)
15
19
16
20
// sys/resource.h
@@ -23,6 +27,24 @@ const (
23
27
cpUStates = 5
24
28
)
25
29
30
+ // mach/machine.h
31
+ const (
32
+ cpuStateUser = 0
33
+ cpuStateSystem = 1
34
+ cpuStateIdle = 2
35
+ cpuStateNice = 3
36
+ cpuStateMax = 4
37
+ )
38
+
39
+ // mach/processor_info.h
40
+ const (
41
+ processorCpuLoadInfo = 2
42
+ )
43
+
44
+ type hostCpuLoadInfoData struct {
45
+ cpuTicks [cpuStateMax ]uint32
46
+ }
47
+
26
48
// default value. from time.h
27
49
var ClocksPerSec = float64 (128 )
28
50
@@ -39,11 +61,17 @@ func Times(percpu bool) ([]TimesStat, error) {
39
61
}
40
62
41
63
func TimesWithContext (ctx context.Context , percpu bool ) ([]TimesStat , error ) {
64
+ lib , err := common .NewLibrary (common .Kernel )
65
+ if err != nil {
66
+ return nil , err
67
+ }
68
+ defer lib .Close ()
69
+
42
70
if percpu {
43
- return perCPUTimes ()
71
+ return perCPUTimes (lib )
44
72
}
45
73
46
- return allCPUTimes ()
74
+ return allCPUTimes (lib )
47
75
}
48
76
49
77
// Returns only one CPUInfoStat on FreeBSD
@@ -115,3 +143,63 @@ func CountsWithContext(ctx context.Context, logical bool) (int, error) {
115
143
116
144
return int (count ), nil
117
145
}
146
+
147
+ func perCPUTimes (machLib * common.Library ) ([]TimesStat , error ) {
148
+ machHostSelf := common .GetFunc [common.MachHostSelfFunc ](machLib , common .MachHostSelfSym )
149
+ machTaskSelf := common .GetFunc [common.MachTaskSelfFunc ](machLib , common .MachTaskSelfSym )
150
+ hostProcessorInfo := common .GetFunc [common.HostProcessorInfoFunc ](machLib , common .HostProcessorInfoSym )
151
+ vmDeallocate := common .GetFunc [common.VMDeallocateFunc ](machLib , common .VMDeallocateSym )
152
+
153
+ var count , ncpu uint32
154
+ var cpuload * hostCpuLoadInfoData
155
+
156
+ status := hostProcessorInfo (machHostSelf (), processorCpuLoadInfo , & ncpu , uintptr (unsafe .Pointer (& cpuload )), & count )
157
+
158
+ if status != common .KERN_SUCCESS {
159
+ return nil , fmt .Errorf ("host_processor_info error=%d" , status )
160
+ }
161
+
162
+ defer vmDeallocate (machTaskSelf (), uintptr (unsafe .Pointer (cpuload )), uintptr (ncpu ))
163
+
164
+ ret := []TimesStat {}
165
+ loads := unsafe .Slice (cpuload , ncpu )
166
+
167
+ for i := 0 ; i < int (ncpu ); i ++ {
168
+ c := TimesStat {
169
+ CPU : fmt .Sprintf ("cpu%d" , i ),
170
+ User : float64 (loads [i ].cpuTicks [cpuStateUser ]) / ClocksPerSec ,
171
+ System : float64 (loads [i ].cpuTicks [cpuStateSystem ]) / ClocksPerSec ,
172
+ Nice : float64 (loads [i ].cpuTicks [cpuStateNice ]) / ClocksPerSec ,
173
+ Idle : float64 (loads [i ].cpuTicks [cpuStateIdle ]) / ClocksPerSec ,
174
+ }
175
+
176
+ ret = append (ret , c )
177
+ }
178
+
179
+ return ret , nil
180
+ }
181
+
182
+ func allCPUTimes (machLib * common.Library ) ([]TimesStat , error ) {
183
+ machHostSelf := common .GetFunc [common.MachHostSelfFunc ](machLib , common .MachHostSelfSym )
184
+ hostStatistics := common .GetFunc [common.HostStatisticsFunc ](machLib , common .HostStatisticsSym )
185
+
186
+ var cpuload hostCpuLoadInfoData
187
+ count := uint32 (cpuStateMax )
188
+
189
+ status := hostStatistics (machHostSelf (), common .HOST_CPU_LOAD_INFO ,
190
+ uintptr (unsafe .Pointer (& cpuload )), & count )
191
+
192
+ if status != common .KERN_SUCCESS {
193
+ return nil , fmt .Errorf ("host_statistics error=%d" , status )
194
+ }
195
+
196
+ c := TimesStat {
197
+ CPU : "cpu-total" ,
198
+ User : float64 (cpuload .cpuTicks [cpuStateUser ]) / ClocksPerSec ,
199
+ System : float64 (cpuload .cpuTicks [cpuStateSystem ]) / ClocksPerSec ,
200
+ Nice : float64 (cpuload .cpuTicks [cpuStateNice ]) / ClocksPerSec ,
201
+ Idle : float64 (cpuload .cpuTicks [cpuStateIdle ]) / ClocksPerSec ,
202
+ }
203
+
204
+ return []TimesStat {c }, nil
205
+ }
0 commit comments