...

Source file src/k8s.io/kubernetes/pkg/kubelet/winstats/perfcounters.go

Documentation: k8s.io/kubernetes/pkg/kubelet/winstats

     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  }
   137  

View as plain text