1
2
3
4
19
20 package winstats
21
22 import (
23 "errors"
24 "fmt"
25 "time"
26 "unsafe"
27
28 "github.com/JeffAshton/win_pdh"
29 )
30
31 const (
32 cpuQuery = "\\Processor(_Total)\\% Processor Time"
33 memoryPrivWorkingSetQuery = "\\Process(_Total)\\Working Set - Private"
34 memoryCommittedBytesQuery = "\\Memory\\Committed Bytes"
35
36
37 perfCounterUpdatePeriod = 10 * time.Second
38
39
40
41 defaultCachePeriod = 10 * time.Second
42 )
43
44 type perfCounter interface {
45 getData() (uint64, error)
46 getDataList() (map[string]uint64, error)
47 }
48
49 type perfCounterImpl struct {
50 queryHandle win_pdh.PDH_HQUERY
51 counterHandle win_pdh.PDH_HCOUNTER
52 }
53
54 func newPerfCounter(counter string) (perfCounter, error) {
55 var queryHandle win_pdh.PDH_HQUERY
56 var counterHandle win_pdh.PDH_HCOUNTER
57
58 ret := win_pdh.PdhOpenQuery(0, 0, &queryHandle)
59 if ret != win_pdh.ERROR_SUCCESS {
60 return nil, errors.New("unable to open query through DLL call")
61 }
62
63 ret = win_pdh.PdhAddEnglishCounter(queryHandle, counter, 0, &counterHandle)
64 if ret != win_pdh.ERROR_SUCCESS {
65 return nil, fmt.Errorf("unable to add process counter: %s. Error code is %x", counter, ret)
66 }
67
68 ret = win_pdh.PdhCollectQueryData(queryHandle)
69 if ret != win_pdh.ERROR_SUCCESS {
70 return nil, fmt.Errorf("unable to collect data from counter. Error code is %x", ret)
71 }
72
73 return &perfCounterImpl{
74 queryHandle: queryHandle,
75 counterHandle: counterHandle,
76 }, nil
77 }
78
79
80 func (p *perfCounterImpl) getData() (uint64, error) {
81 filledBuf, bufCount, err := p.getQueriedData()
82 if err != nil {
83 return 0, err
84 }
85
86 var data uint64 = 0
87 for i := 0; i < int(bufCount); i++ {
88 c := filledBuf[i]
89 data = uint64(c.FmtValue.DoubleValue)
90 }
91
92 return data, nil
93 }
94
95
96 func (p *perfCounterImpl) getDataList() (map[string]uint64, error) {
97 filledBuf, bufCount, err := p.getQueriedData()
98 if err != nil {
99 return nil, err
100 }
101
102 data := map[string]uint64{}
103 for i := 0; i < int(bufCount); i++ {
104 c := filledBuf[i]
105 value := uint64(c.FmtValue.DoubleValue)
106 name := win_pdh.UTF16PtrToString(c.SzName)
107 data[name] = value
108 }
109
110 return data, nil
111 }
112
113
114 func (p *perfCounterImpl) getQueriedData() ([]win_pdh.PDH_FMT_COUNTERVALUE_ITEM_DOUBLE, uint32, error) {
115 ret := win_pdh.PdhCollectQueryData(p.queryHandle)
116 if ret != win_pdh.ERROR_SUCCESS {
117 return nil, 0, fmt.Errorf("unable to collect data from counter. Error code is %x", ret)
118 }
119
120 var bufSize, bufCount uint32
121 var size = uint32(unsafe.Sizeof(win_pdh.PDH_FMT_COUNTERVALUE_ITEM_DOUBLE{}))
122 var emptyBuf [1]win_pdh.PDH_FMT_COUNTERVALUE_ITEM_DOUBLE
123
124 ret = win_pdh.PdhGetFormattedCounterArrayDouble(p.counterHandle, &bufSize, &bufCount, &emptyBuf[0])
125 if ret != win_pdh.PDH_MORE_DATA {
126 return nil, 0, fmt.Errorf("unable to collect data from counter. Error code is %x", ret)
127 }
128
129 filledBuf := make([]win_pdh.PDH_FMT_COUNTERVALUE_ITEM_DOUBLE, bufCount*size)
130 ret = win_pdh.PdhGetFormattedCounterArrayDouble(p.counterHandle, &bufSize, &bufCount, &filledBuf[0])
131 if ret != win_pdh.ERROR_SUCCESS {
132 return nil, 0, fmt.Errorf("unable to collect data from counter. Error code is %x", ret)
133 }
134
135 return filledBuf, bufCount, nil
136 }
137
View as plain text