k8s.io/kubernetes@v1.29.3/pkg/kubelet/winstats/perfcounters.go (about) 1 //go:build windows 2 // +build windows 3 4 /* 5 Copyright 2017 The Kubernetes Authors. 6 7 Licensed under the Apache License, Version 2.0 (the "License"); 8 you may not use this file except in compliance with the License. 9 You may obtain a copy of the License at 10 11 http://www.apache.org/licenses/LICENSE-2.0 12 13 Unless required by applicable law or agreed to in writing, software 14 distributed under the License is distributed on an "AS IS" BASIS, 15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 See the License for the specific language governing permissions and 17 limitations under the License. 18 */ 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 // Perf counters are updated 10 seconds. This is the same as the default cadvisor housekeeping interval 36 // set at https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/cadvisor/cadvisor_linux.go 37 perfCounterUpdatePeriod = 10 * time.Second 38 // defaultCachePeriod is the default cache period for each cpuUsage. 39 // This matches with the cadvisor setting and the time interval we use for containers. 40 // see https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/cadvisor/cadvisor_linux.go#L63 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 // getData is used for getting data without * in counter name. 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 // getDataList is used for getting data with * in counter name. 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 // getQueriedData is used for getting data using the given query handle. 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 // need at least 1 addressable null ptr. 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 }