mirror of
https://github.com/go-kratos/kratos.git
synced 2025-03-17 21:07:54 +02:00
fix cpu painc bug
This commit is contained in:
parent
aad6ecf1b6
commit
69282c4c87
1
go.mod
1
go.mod
@ -24,6 +24,7 @@ require (
|
||||
github.com/prometheus/client_golang v0.9.2
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001 // indirect
|
||||
github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec // indirect
|
||||
github.com/shirou/gopsutil v2.18.12+incompatible // indirect
|
||||
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726
|
||||
github.com/sirupsen/logrus v1.4.1
|
||||
github.com/stretchr/testify v1.3.0
|
||||
|
2
go.sum
2
go.sum
@ -86,6 +86,8 @@ github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001 h1:YDeskXpkN
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec h1:6ncX5ko6B9LntYM0YBRXkiSaZMmLYeZ/NWcmeB43mMY=
|
||||
github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
|
||||
github.com/shirou/gopsutil v2.18.12+incompatible h1:1eaJvGomDnH74/5cF4CTmTbLHAriGFsTZppLXDX93OM=
|
||||
github.com/shirou/gopsutil v2.18.12+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726 h1:xT+JlYxNGqyT+XcU8iUrN18JYed2TvG9yN5ULG2jATM=
|
||||
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
|
||||
github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
|
||||
|
@ -1,5 +1,3 @@
|
||||
// +build linux
|
||||
|
||||
package cpu
|
||||
|
||||
import (
|
||||
|
@ -1,5 +1,3 @@
|
||||
// +build linux
|
||||
|
||||
package cpu
|
||||
|
||||
import (
|
||||
@ -12,12 +10,97 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type cgroupCPU struct {
|
||||
frequency uint64
|
||||
quota float64
|
||||
cores uint64
|
||||
|
||||
preSystem uint64
|
||||
preTotal uint64
|
||||
usage uint64
|
||||
}
|
||||
|
||||
func newCgroupCPU() (cpu *cgroupCPU, err error) {
|
||||
cpus, err := perCPUUsage()
|
||||
if err != nil {
|
||||
err = errors.Errorf("perCPUUsage() failed!err:=%v", err)
|
||||
return
|
||||
}
|
||||
cores := uint64(len(cpus))
|
||||
|
||||
sets, err := cpuSets()
|
||||
if err != nil {
|
||||
err = errors.Errorf("cpuSets() failed!err:=%v", err)
|
||||
return
|
||||
}
|
||||
quota := float64(len(sets))
|
||||
cq, err := cpuQuota()
|
||||
if err == nil && cq != -1 {
|
||||
var period uint64
|
||||
if period, err = cpuPeriod(); err != nil {
|
||||
err = errors.Errorf("cpuPeriod() failed!err:=%v", err)
|
||||
return
|
||||
}
|
||||
limit := float64(cq) / float64(period)
|
||||
if limit < quota {
|
||||
quota = limit
|
||||
}
|
||||
}
|
||||
maxFreq := cpuMaxFreq()
|
||||
|
||||
preSystem, err := systemCPUUsage()
|
||||
if err != nil {
|
||||
err = errors.Errorf("systemCPUUsage() failed!err:=%v", err)
|
||||
return
|
||||
}
|
||||
preTotal, err := totalCPUUsage()
|
||||
if err != nil {
|
||||
err = errors.Errorf("totalCPUUsage() failed!err:=%v", err)
|
||||
}
|
||||
cpu = &cgroupCPU{
|
||||
frequency: maxFreq,
|
||||
quota: quota,
|
||||
cores: cores,
|
||||
preSystem: preSystem,
|
||||
preTotal: preTotal,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (cpu *cgroupCPU) Usage() (u uint64, err error) {
|
||||
var (
|
||||
total uint64
|
||||
system uint64
|
||||
)
|
||||
total, err = totalCPUUsage()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
system, err = systemCPUUsage()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if system != cpu.preSystem {
|
||||
u = uint64(float64((total-cpu.preTotal)*cpu.cores*1e3) / (float64(system-cpu.preSystem) * cpu.quota))
|
||||
}
|
||||
cpu.preSystem = system
|
||||
cpu.preTotal = total
|
||||
return
|
||||
}
|
||||
|
||||
func (cpu *cgroupCPU) Info() Info {
|
||||
return Info{
|
||||
Frequency: cpu.frequency,
|
||||
Quota: cpu.quota,
|
||||
}
|
||||
}
|
||||
|
||||
const nanoSecondsPerSecond = 1e9
|
||||
|
||||
// ErrNoCFSLimit is no quota limit
|
||||
var ErrNoCFSLimit = errors.Errorf("no quota limit")
|
||||
|
||||
var clockTicksPerSecond = uint64(GetClockTicks())
|
||||
var clockTicksPerSecond = uint64(getClockTicks())
|
||||
|
||||
// systemCPUUsage returns the host system's cpu usage in
|
||||
// nanoseconds. An error is returned if the format of the underlying
|
||||
@ -145,3 +228,16 @@ func cpuMaxFreq() uint64 {
|
||||
}
|
||||
return feq
|
||||
}
|
||||
|
||||
//GetClockTicks get the OS's ticks per second
|
||||
func getClockTicks() int {
|
||||
// TODO figure out a better alternative for platforms where we're missing cgo
|
||||
//
|
||||
// TODO Windows. This could be implemented using Win32 QueryPerformanceFrequency().
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms644905(v=vs.85).aspx
|
||||
//
|
||||
// An example of its usage can be found here.
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx
|
||||
|
||||
return 100
|
||||
}
|
@ -6,82 +6,45 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
cores uint64
|
||||
maxFreq uint64
|
||||
quota float64
|
||||
usage uint64
|
||||
|
||||
preSystem uint64
|
||||
preTotal uint64
|
||||
const (
|
||||
interval time.Duration = time.Millisecond * 500
|
||||
)
|
||||
|
||||
func init() {
|
||||
cpus, err := perCPUUsage()
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("stat/sys/cpu: perCPUUsage() failed!err:=%v", err))
|
||||
}
|
||||
cores = uint64(len(cpus))
|
||||
var (
|
||||
stats CPU
|
||||
usage uint64
|
||||
)
|
||||
|
||||
sets, err := cpuSets()
|
||||
type CPU interface {
|
||||
Usage() (u uint64, e error)
|
||||
Info() Info
|
||||
}
|
||||
|
||||
func init() {
|
||||
var (
|
||||
err error
|
||||
)
|
||||
stats, err = newCgroupCPU()
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("stat/sys/cpu: cpuSets() failed!err:=%v", err))
|
||||
}
|
||||
quota = float64(len(sets))
|
||||
cq, err := cpuQuota()
|
||||
if err == nil {
|
||||
if cq != -1 {
|
||||
var period uint64
|
||||
if period, err = cpuPeriod(); err != nil {
|
||||
panic(fmt.Errorf("stat/sys/cpu: cpuPeriod() failed!err:=%v", err))
|
||||
}
|
||||
limit := float64(cq) / float64(period)
|
||||
if limit < quota {
|
||||
quota = limit
|
||||
}
|
||||
fmt.Printf("cgroup cpu init failed(%v),switch to psutil cpu\n", err)
|
||||
stats, err = newPsutilCPU(interval)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("cgroup cpu init failed!err:=%v", err))
|
||||
}
|
||||
}
|
||||
maxFreq = cpuMaxFreq()
|
||||
|
||||
preSystem, err = systemCPUUsage()
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("sys/cpu: systemCPUUsage() failed!err:=%v", err))
|
||||
}
|
||||
preTotal, err = totalCPUUsage()
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("sys/cpu: totalCPUUsage() failed!err:=%v", err))
|
||||
}
|
||||
|
||||
go func() {
|
||||
ticker := time.NewTicker(time.Millisecond * 250)
|
||||
ticker := time.NewTicker(interval)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
<-ticker.C
|
||||
cpu := refreshCPU()
|
||||
if cpu != 0 {
|
||||
atomic.StoreUint64(&usage, cpu)
|
||||
u, err := stats.Usage()
|
||||
if err == nil && u != 0 {
|
||||
atomic.StoreUint64(&usage, u)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func refreshCPU() (u uint64) {
|
||||
total, err := totalCPUUsage()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
system, err := systemCPUUsage()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if system != preSystem {
|
||||
u = uint64(float64((total-preTotal)*cores*1e3) / (float64(system-preSystem) * quota))
|
||||
}
|
||||
preSystem = system
|
||||
preTotal = total
|
||||
return u
|
||||
}
|
||||
|
||||
// Stat cpu stat.
|
||||
type Stat struct {
|
||||
Usage uint64 // cpu use ratio.
|
||||
@ -100,8 +63,5 @@ func ReadStat(stat *Stat) {
|
||||
|
||||
// GetInfo get cpu info.
|
||||
func GetInfo() Info {
|
||||
return Info{
|
||||
Frequency: maxFreq,
|
||||
Quota: quota,
|
||||
}
|
||||
return stats.Info()
|
||||
}
|
||||
|
@ -1,20 +0,0 @@
|
||||
// +build darwin
|
||||
|
||||
package cpu
|
||||
|
||||
var su uint64 = 10
|
||||
var tu uint64 = 10
|
||||
|
||||
func systemCPUUsage() (usage uint64, err error) {
|
||||
su += 1000
|
||||
return su, nil
|
||||
}
|
||||
func totalCPUUsage() (usage uint64, err error) {
|
||||
tu += 500
|
||||
return tu, nil
|
||||
}
|
||||
func perCPUUsage() (usage []uint64, err error) { return []uint64{10, 10, 10, 10}, nil }
|
||||
func cpuSets() (sets []uint64, err error) { return []uint64{0, 1, 2, 3}, nil }
|
||||
func cpuQuota() (quota int64, err error) { return 100, nil }
|
||||
func cpuPeriod() (peroid uint64, err error) { return 10, nil }
|
||||
func cpuMaxFreq() (feq uint64) { return 10 }
|
@ -1,11 +0,0 @@
|
||||
// +build windows
|
||||
|
||||
package cpu
|
||||
|
||||
func systemCPUUsage() (usage uint64, err error) { return 10, nil }
|
||||
func totalCPUUsage() (usage uint64, err error) { return 10, nil }
|
||||
func perCPUUsage() (usage []uint64, err error) { return []uint64{10, 10, 10, 10}, nil }
|
||||
func cpuSets() (sets []uint64, err error) { return []uint64{0, 1, 2, 3}, nil }
|
||||
func cpuQuota() (quota int64, err error) { return 100, nil }
|
||||
func cpuPeriod() (peroid uint64, err error) { return 10, nil }
|
||||
func cpuMaxFreq() (feq uint64) { return 10 }
|
22
pkg/stat/sys/cpu/cpu_test.go
Normal file
22
pkg/stat/sys/cpu/cpu_test.go
Normal file
@ -0,0 +1,22 @@
|
||||
package cpu
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Test_CPUUsage(t *testing.T) {
|
||||
var stat Stat
|
||||
ReadStat(&stat)
|
||||
fmt.Println(stat)
|
||||
time.Sleep(time.Millisecond * 600)
|
||||
for i := 0; i < 6; i++ {
|
||||
time.Sleep(time.Millisecond * 500)
|
||||
ReadStat(&stat)
|
||||
if stat.Usage == 0 {
|
||||
t.Fatalf("get cpu failed!cpu usage is zero!")
|
||||
}
|
||||
fmt.Println(stat)
|
||||
}
|
||||
}
|
45
pkg/stat/sys/cpu/psutilCPU.go
Normal file
45
pkg/stat/sys/cpu/psutilCPU.go
Normal file
@ -0,0 +1,45 @@
|
||||
package cpu
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/shirou/gopsutil/cpu"
|
||||
)
|
||||
|
||||
type psutilCPU struct {
|
||||
interval time.Duration
|
||||
}
|
||||
|
||||
func newPsutilCPU(interval time.Duration) (cpu *psutilCPU, err error) {
|
||||
cpu = &psutilCPU{interval: interval}
|
||||
_, err = cpu.Usage()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (ps *psutilCPU) Usage() (u uint64, err error) {
|
||||
var percents []float64
|
||||
percents, err = cpu.Percent(ps.interval, false)
|
||||
if err == nil {
|
||||
u = uint64(percents[0] * 10)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (ps *psutilCPU) Info() (info Info) {
|
||||
stats, err := cpu.Info()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
cores, err := cpu.Counts(true)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
info = Info{
|
||||
Frequency: uint64(stats[0].Mhz),
|
||||
Quota: float64(cores),
|
||||
}
|
||||
return
|
||||
}
|
22
pkg/stat/sys/cpu/psutilCPU_test.go
Normal file
22
pkg/stat/sys/cpu/psutilCPU_test.go
Normal file
@ -0,0 +1,22 @@
|
||||
package cpu
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Test_PsutilCPU(t *testing.T) {
|
||||
cpu, err := newPsutilCPU(time.Millisecond * 500)
|
||||
if err != nil {
|
||||
t.Fatalf("newPsutilCPU failed!err:=%v", err)
|
||||
}
|
||||
for i := 0; i < 6; i++ {
|
||||
time.Sleep(time.Millisecond * 500)
|
||||
u, err := cpu.Usage()
|
||||
if u == 0 {
|
||||
t.Fatalf("get cpu from psutil failed!cpu usage is zero!err:=%v", err)
|
||||
}
|
||||
fmt.Println(u)
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
package cpu
|
||||
|
||||
//GetClockTicks get the OS's ticks per second
|
||||
func GetClockTicks() int {
|
||||
// TODO figure out a better alternative for platforms where we're missing cgo
|
||||
//
|
||||
// TODO Windows. This could be implemented using Win32 QueryPerformanceFrequency().
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms644905(v=vs.85).aspx
|
||||
//
|
||||
// An example of its usage can be found here.
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx
|
||||
|
||||
return 100
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user