Skip to content
This repository has been archived by the owner on Oct 12, 2023. It is now read-only.

Commit

Permalink
Fixed CPU stats on windows (#23)
Browse files Browse the repository at this point in the history
  • Loading branch information
timotheeguerin authored Dec 10, 2018
1 parent ff44c52 commit 1d30fd3
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 6 deletions.
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ module github.com/Azure/batch-insights
require (
code.cloudfoundry.org/clock v0.0.0-20180518195852-02e53af36e6c // indirect
github.com/Microsoft/ApplicationInsights-Go v0.4.2
github.com/StackExchange/wmi v0.0.0-20180725035823-b12b22c5341f // indirect
github.com/StackExchange/wmi v0.0.0-20180725035823-b12b22c5341f
github.com/dustin/go-humanize v0.0.0-20180713052910-9f541cc9db5d
github.com/go-ole/go-ole v1.2.1 // indirect
github.com/satori/go.uuid v1.2.0 // indirect
github.com/shirou/gopsutil v2.17.12+incompatible
github.com/shirou/gopsutil v2.18.11+incompatible
golang.org/x/sys v0.0.0-20180907202204-917fdcba135d // indirect
)
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E=
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/shirou/gopsutil v2.17.12+incompatible h1:FNbznluSK3DQggqiVw3wK/tFKJrKlLPBuQ+V8XkkCOc=
github.com/shirou/gopsutil v2.17.12+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shirou/gopsutil v2.18.11+incompatible h1:PMFTKnFTr/YTRW5rbLK4vWALV3a+IGXse5nvhSjztmg=
github.com/shirou/gopsutil v2.18.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
golang.org/x/sys v0.0.0-20180907202204-917fdcba135d h1:kWn1hlsqeUrk6JsLJO0ZFyz9bMg8u85voZlIuc68ZU4=
golang.org/x/sys v0.0.0-20180907202204-917fdcba135d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
4 changes: 2 additions & 2 deletions pkg/batchinsights.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (

"github.com/dustin/go-humanize"

"github.com/shirou/gopsutil/cpu"
"github.com/Azure/batch-insights/pkg/cpu"
"github.com/shirou/gopsutil/disk"
"github.com/shirou/gopsutil/mem"
"github.com/shirou/gopsutil/net"
Expand Down Expand Up @@ -52,7 +52,7 @@ func ListenForStats(poolId string, nodeId string, appInsightsKey string) {
for _ = range time.Tick(STATS_POLL_RATE) {

v, _ := mem.VirtualMemory()
var cpus, err = cpu.Percent(0, true)
var cpus, err = cpu.PerCpuPercent()
if err != nil {
fmt.Println(err)
}
Expand Down
1 change: 1 addition & 0 deletions pkg/cpu/cpu.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package cpu
11 changes: 11 additions & 0 deletions pkg/cpu/cpu_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// +build linux

package cpu

import (
psutils_cpu "github.com/shirou/gopsutil/cpu"
)

func PerCpuPercent() ([]float64, error) {
return psutils_cpu.Percent(0, true)
}
94 changes: 94 additions & 0 deletions pkg/cpu/cpu_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// +build windows

package cpu

import (
"context"
"github.com/StackExchange/wmi"
"time"
)

const Timeout = 3 * time.Second

type CPUStat struct {
value uint64
timestamp uint64
}

var lastCpus map[string]CPUStat = make(map[string]CPUStat)

type win32_PerfRawData_Counters_ProcessorInformation struct {
Name string
PercentDPCTime uint64
PercentIdleTime uint64
PercentUserTime uint64
PercentProcessorTime uint64
PercentInterruptTime uint64
PercentPriorityTime uint64
PercentPrivilegedTime uint64
TimeStamp_Sys100NS uint64
InterruptsPerSec uint32
ProcessorFrequency uint32
DPCRate uint32
}

func PerCpuPercent() ([]float64, error) {
return perCPUPercentWithContext(context.Background())
}

func perCPUPercentWithContext(ctx context.Context) ([]float64, error) {
var ret []float64
stats, err := perfInfoWithContext(ctx)
if err != nil {
return nil, err
}

for _, v := range stats {
last := lastCpus[v.Name]

lastCpus[v.Name] = CPUStat{
value: v.PercentProcessorTime,
timestamp: v.TimeStamp_Sys100NS,
}

if last.timestamp != 0 {
value := (1 - (float64(v.PercentProcessorTime-last.value) / float64(v.TimeStamp_Sys100NS-last.timestamp))) * 100
ret = append(ret, value)
}
}
return ret, nil
}

// PerfInfo returns the performance counter's instance value for ProcessorInformation.
// Name property is the key by which overall, per cpu and per core metric is known.
func perfInfoWithContext(ctx context.Context) ([]win32_PerfRawData_Counters_ProcessorInformation, error) {
var ret []win32_PerfRawData_Counters_ProcessorInformation

q := wmi.CreateQuery(&ret, "WHERE NOT Name LIKE '%_Total'")
err := WMIQueryWithContext(ctx, q, &ret)
if err != nil {
return []win32_PerfRawData_Counters_ProcessorInformation{}, err
}

return ret, err
}

func WMIQueryWithContext(ctx context.Context, query string, dst interface{}, connectServerArgs ...interface{}) error {
if _, ok := ctx.Deadline(); !ok {
ctxTimeout, cancel := context.WithTimeout(ctx, Timeout)
defer cancel()
ctx = ctxTimeout
}

errChan := make(chan error, 1)
go func() {
errChan <- wmi.Query(query, dst, connectServerArgs...)
}()

select {
case <-ctx.Done():
return ctx.Err()
case err := <-errChan:
return err
}
}

0 comments on commit 1d30fd3

Please sign in to comment.