mirror of
https://github.com/oneclickvirt/basics.git
synced 2025-10-08 18:11:02 +08:00
v0.0.7 - 更新支持查询GPU信息
This commit is contained in:
2
.github/workflows/ci.yaml
vendored
2
.github/workflows/ci.yaml
vendored
@@ -24,7 +24,7 @@ jobs:
|
||||
run: |
|
||||
git config --global user.name 'github-actions'
|
||||
git config --global user.email 'github-actions@github.com'
|
||||
TAG="v0.0.6-$(date +'%Y%m%d%H%M%S')"
|
||||
TAG="v0.0.7-$(date +'%Y%m%d%H%M%S')"
|
||||
git tag $TAG
|
||||
git push origin $TAG
|
||||
env:
|
||||
|
@@ -12,10 +12,10 @@ Include: https://github.com/oneclickvirt/gostun
|
||||
- [x] 使用```sysctl```获取CPU信息-特化适配freebsd、openbsd系统
|
||||
- [x] 适配```MacOS```与```Windows```系统的信息查询
|
||||
- [x] 部分Windows10系统下打勾打叉编码错误显示,已判断是Win时使用Y/N显示而不是勾叉
|
||||
- [x] 检测GPU相关信息,参考[ghw](https://github.com/jaypipes/ghw)
|
||||
|
||||
## TODO
|
||||
|
||||
- [ ] 检测GPU相关信息,可参考[ghw](https://github.com/jaypipes/ghw)
|
||||
- [ ] CPUCache的信息需要矫正
|
||||
- [ ] 纯IPV6环境下使用cdn反代获取平台信息
|
||||
|
||||
|
11
go.mod
11
go.mod
@@ -4,6 +4,8 @@ go 1.22.4
|
||||
|
||||
require (
|
||||
github.com/imroc/req/v3 v3.43.7
|
||||
github.com/jaypipes/ghw v0.12.0
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/libp2p/go-nat v0.2.0
|
||||
github.com/oneclickvirt/defaultset v0.0.2-20240624082446
|
||||
github.com/oneclickvirt/gostun v0.0.3-20240702054621
|
||||
@@ -13,8 +15,10 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/StackExchange/wmi v1.2.1 // indirect
|
||||
github.com/andybalholm/brotli v1.1.0 // indirect
|
||||
github.com/cloudflare/circl v1.3.9 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/google/gopacket v1.1.19 // indirect
|
||||
@@ -23,16 +27,21 @@ require (
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/huin/goupnp v1.2.0 // indirect
|
||||
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
|
||||
github.com/jaypipes/pcidb v1.0.0 // indirect
|
||||
github.com/klauspost/compress v1.17.9 // indirect
|
||||
github.com/koron/go-ssdp v0.0.4 // indirect
|
||||
github.com/libp2p/go-netroute v0.2.1 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.19.0 // indirect
|
||||
github.com/pion/dtls/v2 v2.2.7 // indirect
|
||||
github.com/pion/logging v0.2.2 // indirect
|
||||
github.com/pion/stun/v2 v2.0.0 // indirect
|
||||
github.com/pion/transport/v2 v2.2.1 // indirect
|
||||
github.com/pion/transport/v3 v3.0.1 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
||||
github.com/quic-go/qpack v0.4.0 // indirect
|
||||
github.com/quic-go/quic-go v0.45.1 // indirect
|
||||
@@ -50,4 +59,6 @@ require (
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/text v0.16.0 // indirect
|
||||
golang.org/x/tools v0.22.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
howett.net/plist v1.0.0 // indirect
|
||||
)
|
||||
|
33
go.sum
33
go.sum
@@ -1,3 +1,5 @@
|
||||
github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA=
|
||||
github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8=
|
||||
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
|
||||
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||
github.com/cloudflare/circl v1.3.9 h1:QFrlgFYf2Qpi8bSpVPK1HBvWpx16v/1TZivyo7pGuBE=
|
||||
@@ -5,8 +7,11 @@ github.com/cloudflare/circl v1.3.9/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZ
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
||||
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
@@ -14,6 +19,7 @@ github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZ
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
||||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||
github.com/google/pprof v0.0.0-20240625030939-27f56978b8b0 h1:e+8XbKB6IMn8A4OAyZccO4pYfB3s7bt6azNIPE7AnPg=
|
||||
@@ -29,16 +35,33 @@ github.com/imroc/req/v3 v3.43.7 h1:dOcNb9n0X83N5/5/AOkiU+cLhzx8QFXjv5MhikazzQA=
|
||||
github.com/imroc/req/v3 v3.43.7/go.mod h1:SQIz5iYop16MJxbo8ib+4LnostGCok8NQf8ToyQc2xA=
|
||||
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
|
||||
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
||||
github.com/jaypipes/ghw v0.12.0 h1:xU2/MDJfWmBhJnujHY9qwXQLs3DBsf0/Xa9vECY0Tho=
|
||||
github.com/jaypipes/ghw v0.12.0/go.mod h1:jeJGbkRB2lL3/gxYzNYzEDETV1ZJ56OKr+CSeSEym+g=
|
||||
github.com/jaypipes/pcidb v1.0.0 h1:vtZIfkiCUE42oYbJS0TAq9XSfSmcsgo9IdxSm9qzYU8=
|
||||
github.com/jaypipes/pcidb v1.0.0/go.mod h1:TnYUvqhPBzCKnH34KrIX22kAeEbDCSRJ9cqLRCuNDfk=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0=
|
||||
github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk=
|
||||
github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk=
|
||||
github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU=
|
||||
github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/oneclickvirt/defaultset v0.0.2-20240624082446 h1:5Pg3mK/u/vQvSz7anu0nxzrNdELi/AcDAU1mMsmPzyc=
|
||||
github.com/oneclickvirt/defaultset v0.0.2-20240624082446/go.mod h1:e9Jt4tf2sbemCtc84/XgKcHy9EZ2jkc5x2sW1NiJS+E=
|
||||
github.com/oneclickvirt/gostun v0.0.3-20240702054621 h1:IE89eEYV9TJbF94SakQDAxTLIaqX+Tb6ZhJ/CCIP+90=
|
||||
@@ -57,6 +80,8 @@ github.com/pion/transport/v2 v2.2.1 h1:7qYnCBlpgSJNYMbLCKuSY9KbQdBFoETvPNETv0y4N
|
||||
github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g=
|
||||
github.com/pion/transport/v3 v3.0.1 h1:gDTlPJwROfSfz6QfSi0ZmeCSkFcnWWiiR9ES0ouANiM=
|
||||
github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
|
||||
@@ -76,6 +101,7 @@ github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnj
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
@@ -171,6 +197,13 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM=
|
||||
howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
|
||||
|
@@ -1,6 +1,6 @@
|
||||
package model
|
||||
|
||||
const BasicsVersion = "v0.0.6"
|
||||
const BasicsVersion = "v0.0.7"
|
||||
|
||||
var EnableLoger bool
|
||||
|
||||
@@ -119,6 +119,7 @@ type DiskInfo struct {
|
||||
|
||||
type SystemInfo struct {
|
||||
CpuInfo
|
||||
GPUInfo
|
||||
MemoryInfo
|
||||
DiskInfo
|
||||
Platform string // 系统名字 Distro1
|
||||
@@ -135,6 +136,11 @@ type SystemInfo struct {
|
||||
TcpAccelerationMethod string // TCP拥塞控制
|
||||
}
|
||||
|
||||
type GPUInfo struct {
|
||||
GpuModel string
|
||||
GpuStats string
|
||||
}
|
||||
|
||||
type Win32_Processor struct {
|
||||
L2CacheSize uint32
|
||||
L3CacheSize uint32
|
||||
|
87
system/gpu.go
Normal file
87
system/gpu.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/oneclickvirt/basics/model"
|
||||
"github.com/oneclickvirt/basics/system/gpu"
|
||||
gpustat "github.com/oneclickvirt/basics/system/gpu/stat"
|
||||
. "github.com/oneclickvirt/defaultset"
|
||||
)
|
||||
|
||||
var updateGPUStatus int32
|
||||
var gpuStat uint64
|
||||
|
||||
// 获取设备数据的最大尝试次数
|
||||
const maxDeviceDataFetchAttempts = 3
|
||||
|
||||
// 获取主机数据的尝试次数,Key 为 Host 的属性名
|
||||
var hostDataFetchAttempts = map[string]int{
|
||||
"CPU": 0,
|
||||
"GPU": 0,
|
||||
}
|
||||
|
||||
// 获取状态数据的尝试次数,Key 为 HostState 的属性名
|
||||
var statDataFetchAttempts = map[string]int{
|
||||
"CPU": 0,
|
||||
"Load": 0,
|
||||
"GPU": 0,
|
||||
"Temperatures": 0,
|
||||
}
|
||||
|
||||
func atomicStoreFloat64(x *uint64, v float64) {
|
||||
atomic.StoreUint64(x, math.Float64bits(v))
|
||||
}
|
||||
|
||||
func updateGPUStat(gpuStat *uint64, wg *sync.WaitGroup) {
|
||||
if model.EnableLoger {
|
||||
InitLogger()
|
||||
defer Logger.Sync()
|
||||
}
|
||||
defer wg.Done()
|
||||
if !atomic.CompareAndSwapInt32(&updateGPUStatus, 0, 1) {
|
||||
return
|
||||
}
|
||||
defer atomic.StoreInt32(&updateGPUStatus, 0)
|
||||
|
||||
for statDataFetchAttempts["GPU"] < maxDeviceDataFetchAttempts {
|
||||
gs, err := gpustat.GetGPUStat()
|
||||
if err != nil {
|
||||
statDataFetchAttempts["GPU"]++
|
||||
if model.EnableLoger {
|
||||
Logger.Info(fmt.Sprintf("gpustat.GetGPUStat error: %s, attempt: %d", err.Error(), statDataFetchAttempts["GPU"]))
|
||||
}
|
||||
time.Sleep(1 * time.Second) // 等待一段时间再重试
|
||||
} else {
|
||||
statDataFetchAttempts["GPU"] = 0
|
||||
atomicStoreFloat64(gpuStat, gs)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getGPUInfo(ret *model.SystemInfo) (*model.SystemInfo, error) {
|
||||
gpuModels, err := gpu.GetGPUModel()
|
||||
if len(gpuModels) > 0 {
|
||||
if err != nil {
|
||||
hostDataFetchAttempts["GPU"]++
|
||||
return ret, fmt.Errorf("no gpu")
|
||||
} else {
|
||||
hostDataFetchAttempts["GPU"] = 0
|
||||
}
|
||||
ret.GpuModel = gpuModels[0]
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
go updateGPUStat(&gpuStat, &wg)
|
||||
wg.Wait() // 等待 updateGPUStat 完成
|
||||
ret.GpuStats = fmt.Sprintf("%f", math.Float64frombits(gpuStat))
|
||||
return ret, nil
|
||||
} else {
|
||||
hostDataFetchAttempts["GPU"]++
|
||||
return ret, fmt.Errorf("no gpu")
|
||||
}
|
||||
}
|
27
system/gpu/gpu.go
Normal file
27
system/gpu/gpu.go
Normal file
@@ -0,0 +1,27 @@
|
||||
//go:build !darwin
|
||||
// +build !darwin
|
||||
|
||||
package gpu
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/jaypipes/ghw"
|
||||
)
|
||||
|
||||
func GetGPUModel() ([]string, error) {
|
||||
var gpuModel []string
|
||||
gi, err := ghw.GPU(ghw.WithDisableWarnings())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, card := range gi.GraphicsCards {
|
||||
if card.DeviceInfo == nil {
|
||||
return nil, errors.New("Cannot find device info")
|
||||
}
|
||||
gpuModel = append(gpuModel, card.DeviceInfo.Product.Name)
|
||||
}
|
||||
|
||||
return gpuModel, nil
|
||||
}
|
53
system/gpu/gpu_darwin.go
Normal file
53
system/gpu/gpu_darwin.go
Normal file
@@ -0,0 +1,53 @@
|
||||
//go:build darwin && !cgo
|
||||
|
||||
package gpu
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func extractGPUInfo(cmd *exec.Cmd) ([]string, error) {
|
||||
gi, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
re := regexp.MustCompile(`"model"\s*=\s*["<]?"([^">]+)"[">]?`)
|
||||
matches := re.FindAllSubmatch(gi, -1)
|
||||
var modelNames []string
|
||||
for _, match := range matches {
|
||||
if len(match) > 1 {
|
||||
modelNames = append(modelNames, string(match[1]))
|
||||
}
|
||||
}
|
||||
return modelNames, nil
|
||||
}
|
||||
|
||||
func GetGPUModel() ([]string, error) {
|
||||
vendorNames := []string{
|
||||
"AMD", "Intel", "Nvidia", "Apple",
|
||||
}
|
||||
|
||||
ioreg := exec.Command("ioreg", "-rd1", "-c", "IOAccelerator")
|
||||
gi, err := extractGPUInfo(ioreg)
|
||||
if err != nil || len(gi) == 0 {
|
||||
ioreg = exec.Command("ioreg", "-rd1", "-c", "IOPCIDevice")
|
||||
gi, err = extractGPUInfo(ioreg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var gpuModel []string
|
||||
for _, model := range gi {
|
||||
for _, vendor := range vendorNames {
|
||||
if strings.Contains(model, vendor) {
|
||||
gpuModel = append(gpuModel, model)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return gpuModel, nil
|
||||
}
|
65
system/gpu/gpu_darwin_cgo.go
Normal file
65
system/gpu/gpu_darwin_cgo.go
Normal file
@@ -0,0 +1,65 @@
|
||||
//go:build darwin && cgo
|
||||
|
||||
package gpu
|
||||
|
||||
// #cgo LDFLAGS: -framework IOKit -framework CoreFoundation
|
||||
// #include "stat/gpu_darwin.h"
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func GoStrings(argc C.int, argv **C.char) []string {
|
||||
length := int(argc)
|
||||
tmpslice := unsafe.Slice(argv, length)
|
||||
gostrings := make([]string, length)
|
||||
for i, s := range tmpslice {
|
||||
gostrings[i] = C.GoString(s)
|
||||
}
|
||||
return gostrings
|
||||
}
|
||||
|
||||
func extractGPUInfo(key *C.char) ([]string, error) {
|
||||
devices := C.find_devices(key)
|
||||
if devices != nil {
|
||||
defer C.free(unsafe.Pointer(devices))
|
||||
length := 0
|
||||
for {
|
||||
device := *(**C.char)(unsafe.Pointer(uintptr(unsafe.Pointer(devices)) + uintptr(length)*unsafe.Sizeof(*devices)))
|
||||
if device == nil {
|
||||
break
|
||||
}
|
||||
length++
|
||||
}
|
||||
gpu := GoStrings(C.int(length), devices)
|
||||
return gpu, nil
|
||||
}
|
||||
return nil, errors.New("cannot find key")
|
||||
}
|
||||
|
||||
func GetGPUModel() ([]string, error) {
|
||||
vendorNames := []string{
|
||||
"AMD", "Intel", "Nvidia", "Apple",
|
||||
}
|
||||
|
||||
key := C.CString("model")
|
||||
defer C.free(unsafe.Pointer(key))
|
||||
|
||||
gi, err := extractGPUInfo(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var gpuModel []string
|
||||
for _, model := range gi {
|
||||
for _, vendor := range vendorNames {
|
||||
if strings.Contains(model, vendor) {
|
||||
gpuModel = append(gpuModel, model)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return gpuModel, nil
|
||||
}
|
66
system/gpu/stat/amd_rocm_smi.go
Normal file
66
system/gpu/stat/amd_rocm_smi.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package stat
|
||||
|
||||
// Modified from https://github.com/influxdata/telegraf/blob/master/plugins/inputs/amd_rocm_smi/amd_rocm_smi.go
|
||||
// Original License: MIT
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
)
|
||||
|
||||
type ROCmSMI struct {
|
||||
BinPath string
|
||||
}
|
||||
|
||||
func (rsmi *ROCmSMI) Gather() ([]float64, error) {
|
||||
data := rsmi.pollROCmSMI()
|
||||
|
||||
return gatherROCmSMI(data)
|
||||
}
|
||||
|
||||
func (rsmi *ROCmSMI) Start() error {
|
||||
if _, err := os.Stat(rsmi.BinPath); os.IsNotExist(err) {
|
||||
binPath, err := exec.LookPath("rocm-smi")
|
||||
if err != nil {
|
||||
return errors.New("Didn't find the adequate tool to query GPU utilization")
|
||||
}
|
||||
rsmi.BinPath = binPath
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rsmi *ROCmSMI) pollROCmSMI() []byte {
|
||||
cmd := exec.Command(rsmi.BinPath,
|
||||
"-u",
|
||||
"--json",
|
||||
)
|
||||
gs, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return gs
|
||||
}
|
||||
|
||||
func gatherROCmSMI(ret []byte) ([]float64, error) {
|
||||
var gpus map[string]GPU
|
||||
var percentage []float64
|
||||
Json := jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
err := Json.Unmarshal(ret, &gpus)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, gpu := range gpus {
|
||||
gp, _ := strconv.ParseFloat(gpu.GpuUsePercentage, 64)
|
||||
percentage = append(percentage, gp)
|
||||
}
|
||||
|
||||
return percentage, nil
|
||||
}
|
||||
|
||||
type GPU struct {
|
||||
GpuUsePercentage string `json:"GPU use (%)"`
|
||||
}
|
144
system/gpu/stat/gpu_darwin.c
Normal file
144
system/gpu/stat/gpu_darwin.c
Normal file
@@ -0,0 +1,144 @@
|
||||
#include "gpu_darwin.h"
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define IOSERVICE_GPU "IOAccelerator"
|
||||
#define IOSERVICE_PCI "IOPCIDevice"
|
||||
|
||||
void *find_properties(io_registry_entry_t service, int depth, CFStringRef key,
|
||||
CFStringRef dict_key) {
|
||||
CFTypeRef properties = IORegistryEntrySearchCFProperty(
|
||||
service, kIOServicePlane, key, kCFAllocatorDefault,
|
||||
kIORegistryIterateRecursively);
|
||||
|
||||
if (properties) {
|
||||
if (CFGetTypeID(properties) == CFStringGetTypeID()) {
|
||||
CFStringRef cfStr = (CFStringRef)properties;
|
||||
char buffer[1024];
|
||||
CFStringGetCString(cfStr, buffer, sizeof(buffer), kCFStringEncodingUTF8);
|
||||
CFRelease(properties);
|
||||
return strdup(buffer);
|
||||
} else if (CFGetTypeID(properties) == CFDictionaryGetTypeID()) {
|
||||
CFDictionaryRef cfDict = (CFDictionaryRef)properties;
|
||||
CFNumberRef cfValue = (CFNumberRef)CFDictionaryGetValue(cfDict, dict_key);
|
||||
if (cfValue == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
int value;
|
||||
if (!CFNumberGetValue(cfValue, kCFNumberIntType, &value)) {
|
||||
return NULL;
|
||||
}
|
||||
return (void *)(intptr_t)value;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char **find_devices(char *key) {
|
||||
io_service_t io_reg_err;
|
||||
io_iterator_t iterator;
|
||||
int capacity = 10;
|
||||
|
||||
char **cards = malloc(capacity * sizeof(char *));
|
||||
if (!cards) {
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
io_reg_err = IOServiceGetMatchingServices(
|
||||
kIOMainPortDefault, IOServiceMatching(IOSERVICE_GPU), &iterator);
|
||||
if (io_reg_err != KERN_SUCCESS) {
|
||||
printf("Error getting GPU entry\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
io_object_t service;
|
||||
int index = 0;
|
||||
while ((service = IOIteratorNext(iterator)) != MACH_PORT_NULL) {
|
||||
CFStringRef cfStr = CFStringCreateWithCString(kCFAllocatorDefault, key,
|
||||
kCFStringEncodingUTF8);
|
||||
char *result = find_properties(service, 0, cfStr, CFSTR(""));
|
||||
CFRelease(cfStr);
|
||||
IOObjectRelease(service);
|
||||
|
||||
if (result != NULL) {
|
||||
if (index >= capacity) {
|
||||
capacity += 1;
|
||||
char **new_cards = (char **)realloc(cards, capacity * sizeof(char *));
|
||||
if (!new_cards) {
|
||||
fprintf(stderr, "Memory reallocation failed\n");
|
||||
for (int i = 0; i < index; i++) {
|
||||
free(cards[i]);
|
||||
}
|
||||
free(cards);
|
||||
free(result);
|
||||
return NULL;
|
||||
}
|
||||
cards = new_cards;
|
||||
}
|
||||
cards[index] = result;
|
||||
index++;
|
||||
}
|
||||
|
||||
if (result == NULL && strcmp(key, "model") == 0) {
|
||||
IOObjectRelease(iterator);
|
||||
|
||||
io_reg_err = IOServiceGetMatchingServices(
|
||||
kIOMainPortDefault, IOServiceMatching(IOSERVICE_PCI), &iterator);
|
||||
if (io_reg_err != KERN_SUCCESS) {
|
||||
printf("Error getting PCI entry\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
IOObjectRelease(iterator);
|
||||
|
||||
char **result_cards = (char **)realloc(cards, sizeof(char *) * (index + 1));
|
||||
if (!result_cards) {
|
||||
fprintf(stderr, "Memory reallocation failed\n");
|
||||
for (int i = 0; i < index; i++) {
|
||||
free(cards[i]);
|
||||
}
|
||||
free(cards);
|
||||
return NULL;
|
||||
}
|
||||
result_cards[index] = NULL;
|
||||
|
||||
return result_cards;
|
||||
}
|
||||
|
||||
int find_utilization(char *key, char *dict_key) {
|
||||
void *result_ptr;
|
||||
io_service_t io_reg_err;
|
||||
io_iterator_t iterator;
|
||||
|
||||
io_reg_err = IOServiceGetMatchingServices(
|
||||
kIOMainPortDefault, IOServiceMatching(IOSERVICE_GPU), &iterator);
|
||||
if (io_reg_err != KERN_SUCCESS) {
|
||||
printf("Error getting GPU entry\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
io_object_t service = IOIteratorNext(iterator);
|
||||
if (service != MACH_PORT_NULL) {
|
||||
CFStringRef cfStr = CFStringCreateWithCString(kCFAllocatorDefault, key,
|
||||
kCFStringEncodingUTF8);
|
||||
CFStringRef cfDictStr = CFStringCreateWithCString(
|
||||
kCFAllocatorDefault, dict_key, kCFStringEncodingUTF8);
|
||||
result_ptr = find_properties(service, 0, cfStr, cfDictStr);
|
||||
CFRelease(cfStr);
|
||||
CFRelease(cfDictStr);
|
||||
}
|
||||
|
||||
IOObjectRelease(service);
|
||||
IOObjectRelease(iterator);
|
||||
|
||||
if (result_ptr == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int)(intptr_t)result_ptr;
|
||||
}
|
15
system/gpu/stat/gpu_darwin.h
Normal file
15
system/gpu/stat/gpu_darwin.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef __SMC_H__
|
||||
#define __SMC_H__ 1
|
||||
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
#if (defined __MAC_OS_X_VERSION_MIN_REQUIRED) && (__MAC_OS_X_VERSION_MIN_REQUIRED < 120000)
|
||||
#define kIOMainPortDefault kIOMasterPortDefault
|
||||
#endif
|
||||
|
||||
void *find_properties(io_registry_entry_t, int, CFStringRef, CFStringRef);
|
||||
char **find_devices(char *);
|
||||
int find_utilization(char *, char *);
|
||||
|
||||
#endif
|
85
system/gpu/stat/nvidia_smi.go
Normal file
85
system/gpu/stat/nvidia_smi.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package stat
|
||||
|
||||
// Modified from https://github.com/influxdata/telegraf/blob/master/plugins/inputs/nvidia_smi/nvidia_smi.go
|
||||
// Original License: MIT
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type NvidiaSMI struct {
|
||||
BinPath string
|
||||
}
|
||||
|
||||
func (smi *NvidiaSMI) Gather() ([]float64, error) {
|
||||
data := smi.pollNvidiaSMI()
|
||||
|
||||
return smi.parse(data)
|
||||
}
|
||||
|
||||
func (smi *NvidiaSMI) Start() error {
|
||||
if _, err := os.Stat(smi.BinPath); os.IsNotExist(err) {
|
||||
binPath, err := exec.LookPath("nvidia-smi")
|
||||
if err != nil {
|
||||
return errors.New("Didn't find the adequate tool to query GPU utilization")
|
||||
}
|
||||
smi.BinPath = binPath
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (smi *NvidiaSMI) pollNvidiaSMI() []byte {
|
||||
cmd := exec.Command(smi.BinPath,
|
||||
"-q",
|
||||
"-x",
|
||||
)
|
||||
gs, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return gs
|
||||
}
|
||||
|
||||
func (smi *NvidiaSMI) parse(data []byte) ([]float64, error) {
|
||||
var s smistat
|
||||
var percentage []float64
|
||||
|
||||
err := xml.Unmarshal(data, &s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, gpu := range s.GPUs {
|
||||
gp, _ := parsePercentage(gpu.Utilization.GpuUtil)
|
||||
percentage = append(percentage, gp)
|
||||
}
|
||||
|
||||
return percentage, nil
|
||||
}
|
||||
|
||||
func parsePercentage(p string) (float64, error) {
|
||||
per := strings.ReplaceAll(p, " ", "")
|
||||
|
||||
t := strings.TrimSuffix(per, "%")
|
||||
|
||||
value, err := strconv.ParseFloat(t, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
type nGPU struct {
|
||||
Utilization struct {
|
||||
GpuUtil string `xml:"gpu_util"`
|
||||
} `xml:"utilization"`
|
||||
}
|
||||
type smistat struct {
|
||||
GPUs []nGPU `xml:"gpu"`
|
||||
}
|
36
system/gpu/stat/stat_darwin.go
Normal file
36
system/gpu/stat/stat_darwin.go
Normal file
@@ -0,0 +1,36 @@
|
||||
//go:build darwin && !cgo
|
||||
|
||||
package stat
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func extractGPUStat(cmd *exec.Cmd) ([]float64, error) {
|
||||
gs, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
re := regexp.MustCompile(`"Device Utilization %"\s*=\s*(\d+)`)
|
||||
matches := re.FindAllSubmatch(gs, -1)
|
||||
var u []float64
|
||||
for _, match := range matches {
|
||||
if len(match) > 1 {
|
||||
p, _ := strconv.ParseFloat(string(match[1]), 64)
|
||||
u = append(u, p)
|
||||
}
|
||||
}
|
||||
return u, nil
|
||||
}
|
||||
|
||||
func GetGPUStat() (float64, error) {
|
||||
ioreg := exec.Command("ioreg", "-rd1", "-c", "IOAccelerator")
|
||||
gs, err := extractGPUStat(ioreg)
|
||||
if err != nil || len(gs) == 0 {
|
||||
return 0, err
|
||||
}
|
||||
return gs[0], nil
|
||||
}
|
25
system/gpu/stat/stat_darwin_cgo.go
Normal file
25
system/gpu/stat/stat_darwin_cgo.go
Normal file
@@ -0,0 +1,25 @@
|
||||
//go:build darwin && cgo
|
||||
|
||||
package stat
|
||||
|
||||
// #cgo LDFLAGS: -framework IOKit -framework CoreFoundation
|
||||
// #include "gpu_darwin.h"
|
||||
import "C"
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func extractGPUStat(key *C.char, dict_key *C.char) (int, error) {
|
||||
utilization := C.find_utilization(key, dict_key)
|
||||
return int(utilization), nil
|
||||
}
|
||||
|
||||
func GetGPUStat() (float64, error) {
|
||||
key := C.CString("PerformanceStatistics")
|
||||
dict_key := C.CString("Device Utilization %")
|
||||
defer C.free(unsafe.Pointer(key))
|
||||
defer C.free(unsafe.Pointer(dict_key))
|
||||
|
||||
gs, _ := extractGPUStat(key, dict_key)
|
||||
return float64(gs), nil
|
||||
}
|
7
system/gpu/stat/stat_freebsd.go
Normal file
7
system/gpu/stat/stat_freebsd.go
Normal file
@@ -0,0 +1,7 @@
|
||||
//go:build freebsd
|
||||
|
||||
package stat
|
||||
|
||||
func GetGPUStat() (float64, error) {
|
||||
return 0, nil
|
||||
}
|
44
system/gpu/stat/stat_linux.go
Normal file
44
system/gpu/stat/stat_linux.go
Normal file
@@ -0,0 +1,44 @@
|
||||
//go:build linux
|
||||
|
||||
package stat
|
||||
|
||||
func getNvidiaStat() ([]float64, error) {
|
||||
smi := &NvidiaSMI{
|
||||
BinPath: "/usr/bin/nvidia-smi",
|
||||
}
|
||||
err1 := smi.Start()
|
||||
if err1 != nil {
|
||||
return nil, err1
|
||||
}
|
||||
data, err2 := smi.Gather()
|
||||
if err2 != nil {
|
||||
return nil, err2
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func getAMDStat() ([]float64, error) {
|
||||
rsmi := &ROCmSMI{
|
||||
BinPath: "/opt/rocm/bin/rocm-smi",
|
||||
}
|
||||
err1 := rsmi.Start()
|
||||
if err1 != nil {
|
||||
return nil, err1
|
||||
}
|
||||
data, err2 := rsmi.Gather()
|
||||
if err2 != nil {
|
||||
return nil, err2
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func GetGPUStat() (float64, error) {
|
||||
gs, err := getNvidiaStat()
|
||||
if err != nil {
|
||||
gs, err = getAMDStat()
|
||||
}
|
||||
if err != nil || len(gs) == 0 {
|
||||
return 0, err
|
||||
}
|
||||
return gs[0], nil
|
||||
}
|
151
system/gpu/stat/stat_windows.go
Normal file
151
system/gpu/stat/stat_windows.go
Normal file
@@ -0,0 +1,151 @@
|
||||
//go:build windows
|
||||
|
||||
// Modified from https://github.com/shirou/gopsutil/blob/master/internal/common/common_windows.go
|
||||
// Original License: BSD-3-Clause
|
||||
|
||||
package stat
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
const (
|
||||
ERROR_SUCCESS = 0
|
||||
PDH_FMT_DOUBLE = 0x00000200
|
||||
PDH_MORE_DATA = 0x800007d2
|
||||
PDH_VAILD_DATA = 0x00000000
|
||||
PDH_NEW_DATA = 0x00000001
|
||||
PDH_NO_DATA = 0x800007d5
|
||||
)
|
||||
|
||||
var (
|
||||
modPdh = windows.NewLazySystemDLL("pdh.dll")
|
||||
|
||||
pdhOpenQuery = modPdh.NewProc("PdhOpenQuery")
|
||||
pdhCollectQueryData = modPdh.NewProc("PdhCollectQueryData")
|
||||
pdhGetFormattedCounterArrayW = modPdh.NewProc("PdhGetFormattedCounterArrayW")
|
||||
pdhAddEnglishCounterW = modPdh.NewProc("PdhAddEnglishCounterW")
|
||||
)
|
||||
|
||||
type PDH_FMT_COUNTERVALUE_DOUBLE struct {
|
||||
CStatus uint32
|
||||
DoubleValue float64
|
||||
}
|
||||
|
||||
type PDH_FMT_COUNTERVALUE_ITEM_DOUBLE struct {
|
||||
SzName *uint16
|
||||
FmtValue PDH_FMT_COUNTERVALUE_DOUBLE
|
||||
}
|
||||
|
||||
// https://github.com/influxdata/telegraf/blob/master/plugins/inputs/win_perf_counters/performance_query.go
|
||||
func getCounterArrayValue(initialBufSize uint32, counter *win32PerformanceCounter) ([]float64, error) {
|
||||
for buflen := initialBufSize; buflen <= 100*1024*1024; buflen *= 2 {
|
||||
time.Sleep(10 * time.Millisecond) // GPU 查询必须设置间隔,否则数据不准
|
||||
s, _, err := pdhCollectQueryData.Call(uintptr(counter.Query))
|
||||
if s != 0 && err != nil {
|
||||
if s == PDH_NO_DATA {
|
||||
return nil, fmt.Errorf("%w: this counter has not data", err)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
buf := make([]byte, buflen)
|
||||
size := buflen
|
||||
var itemCount uint32
|
||||
r, _, _ := pdhGetFormattedCounterArrayW.Call(uintptr(counter.Counter), PDH_FMT_DOUBLE, uintptr(unsafe.Pointer(&size)), uintptr(unsafe.Pointer(&itemCount)), uintptr(unsafe.Pointer(&buf[0])))
|
||||
if r == ERROR_SUCCESS {
|
||||
items := (*[1 << 20]PDH_FMT_COUNTERVALUE_ITEM_DOUBLE)(unsafe.Pointer(&buf[0]))[:itemCount:itemCount]
|
||||
values := make([]float64, 0, itemCount)
|
||||
for _, item := range items {
|
||||
if item.FmtValue.CStatus == PDH_VAILD_DATA || item.FmtValue.CStatus == PDH_NEW_DATA {
|
||||
val := item.FmtValue.DoubleValue
|
||||
values = append(values, val)
|
||||
}
|
||||
}
|
||||
return values, nil
|
||||
}
|
||||
if r != PDH_MORE_DATA {
|
||||
return nil, fmt.Errorf("pdhGetFormattedCounterArrayW failed with status 0x%X", r)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, errors.New("buffer limit reached")
|
||||
}
|
||||
|
||||
func createQuery() (windows.Handle, error) {
|
||||
var query windows.Handle
|
||||
r, _, err := pdhOpenQuery.Call(0, 0, uintptr(unsafe.Pointer(&query)))
|
||||
if r != ERROR_SUCCESS {
|
||||
return 0, fmt.Errorf("pdhOpenQuery failed with status 0x%X: %v", r, err)
|
||||
}
|
||||
return query, nil
|
||||
}
|
||||
|
||||
type win32PerformanceCounter struct {
|
||||
PostName string
|
||||
CounterName string
|
||||
Query windows.Handle
|
||||
Counter windows.Handle
|
||||
}
|
||||
|
||||
func newWin32PerformanceCounter(postName, counterName string) (*win32PerformanceCounter, error) {
|
||||
query, err := createQuery()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
counter := win32PerformanceCounter{
|
||||
Query: query,
|
||||
PostName: postName,
|
||||
CounterName: counterName,
|
||||
}
|
||||
r, _, err := pdhAddEnglishCounterW.Call(
|
||||
uintptr(counter.Query),
|
||||
uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(counter.CounterName))),
|
||||
0,
|
||||
uintptr(unsafe.Pointer(&counter.Counter)),
|
||||
)
|
||||
if r != ERROR_SUCCESS {
|
||||
return nil, fmt.Errorf("pdhAddEnglishCounterW failed with status 0x%X: %v", r, err)
|
||||
}
|
||||
return &counter, nil
|
||||
}
|
||||
|
||||
func getValue(initialBufSize uint32, counter *win32PerformanceCounter) ([]float64, error) {
|
||||
s, _, err := pdhCollectQueryData.Call(uintptr(counter.Query))
|
||||
if s != 0 && err != nil {
|
||||
if s == PDH_NO_DATA {
|
||||
return nil, fmt.Errorf("%w: this counter has not data", err)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return getCounterArrayValue(initialBufSize, counter)
|
||||
}
|
||||
|
||||
func GetGPUStat() (float64, error) {
|
||||
counter, err := newWin32PerformanceCounter("gpu_utilization", "\\GPU Engine(*engtype_3D)\\Utilization Percentage")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
values, err := getValue(1024, counter)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
tot := sumArray(values)
|
||||
if tot > 100 {
|
||||
tot = 100
|
||||
}
|
||||
return tot, nil
|
||||
}
|
||||
|
||||
func sumArray(arr []float64) float64 {
|
||||
var sum float64
|
||||
for _, value := range arr {
|
||||
sum += value
|
||||
}
|
||||
return sum
|
||||
}
|
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/oneclickvirt/basics/model"
|
||||
"github.com/oneclickvirt/basics/system/utils"
|
||||
. "github.com/oneclickvirt/defaultset"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -18,16 +19,35 @@ var (
|
||||
|
||||
// GetSystemInfo 获取主机硬件信息
|
||||
func GetSystemInfo() *model.SystemInfo {
|
||||
if model.EnableLoger {
|
||||
InitLogger()
|
||||
defer Logger.Sync()
|
||||
}
|
||||
var ret = &model.SystemInfo{}
|
||||
var err error
|
||||
if runtime.GOOS == "darwin" {
|
||||
getMacOSInfo()
|
||||
}
|
||||
// 系统信息查询
|
||||
cpuType, ret.Uptime, ret.Platform, ret.Kernel, ret.Arch, ret.VmType, ret.NatType, ret.TimeZone, _ = getHostInfo()
|
||||
cpuType, ret.Uptime, ret.Platform, ret.Kernel, ret.Arch, ret.VmType, ret.NatType, ret.TimeZone, err = getHostInfo()
|
||||
if model.EnableLoger {
|
||||
Logger.Info(err.Error())
|
||||
}
|
||||
// CPU信息查询
|
||||
ret, _ = getCpuInfo(ret, cpuType)
|
||||
ret, err = getCpuInfo(ret, cpuType)
|
||||
if model.EnableLoger {
|
||||
Logger.Info(err.Error())
|
||||
}
|
||||
// GPU信息查询
|
||||
ret, err = getGPUInfo(ret)
|
||||
if model.EnableLoger {
|
||||
Logger.Info(err.Error())
|
||||
}
|
||||
// 硬盘信息查询
|
||||
ret.DiskTotal, ret.DiskUsage, ret.Percentage, ret.BootPath, _ = getDiskInfo()
|
||||
ret.DiskTotal, ret.DiskUsage, ret.Percentage, ret.BootPath, err = getDiskInfo()
|
||||
if model.EnableLoger {
|
||||
Logger.Info(err.Error())
|
||||
}
|
||||
// 内存信息查询
|
||||
ret.MemoryTotal, ret.MemoryUsage, ret.SwapTotal, ret.SwapUsage, ret.VirtioBalloon, ret.KSM = getMemoryInfo()
|
||||
// 获取负载信息
|
||||
@@ -52,6 +72,12 @@ func CheckSystemInfo(language string) string {
|
||||
if ret.CpuCache != "" {
|
||||
res += " CPU Cache : " + ret.CpuCache + "\n"
|
||||
}
|
||||
if ret.GpuModel != "" {
|
||||
res += " GPU Model : " + ret.GpuModel + "\n"
|
||||
if ret.GpuStats != "" && ret.GpuStats != "0" {
|
||||
res += " GPU Stats : " + ret.GpuStats + "\n"
|
||||
}
|
||||
}
|
||||
if runtime.GOOS != "windows" && runtime.GOOS != "macos" {
|
||||
res += " AES-NI : " + ret.CpuAesNi + "\n"
|
||||
}
|
||||
@@ -95,6 +121,12 @@ func CheckSystemInfo(language string) string {
|
||||
if ret.CpuCache != "" {
|
||||
res += " CPU 缓存 : " + ret.CpuCache + "\n"
|
||||
}
|
||||
if ret.GpuModel != "" {
|
||||
res += " GPU 型号 : " + ret.GpuModel + "\n"
|
||||
if ret.GpuStats != "" && ret.GpuStats != "0" {
|
||||
res += " GPU 状态 : " + ret.GpuStats + "\n"
|
||||
}
|
||||
}
|
||||
if runtime.GOOS != "windows" && runtime.GOOS != "macos" {
|
||||
res += " AES-NI : " + ret.CpuAesNi + "\n"
|
||||
}
|
||||
|
Reference in New Issue
Block a user