1// Copyright 2017 The Prometheus Authors 2// Licensed under the Apache License, Version 2.0 (the "License"); 3// you may not use this file except in compliance with the License. 4// You may obtain a copy of the License at 5// 6// http://www.apache.org/licenses/LICENSE-2.0 7// 8// Unless required by applicable law or agreed to in writing, software 9// distributed under the License is distributed on an "AS IS" BASIS, 10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11// See the License for the specific language governing permissions and 12// limitations under the License. 13 14package procfs 15 16import ( 17 "bufio" 18 "fmt" 19 "io" 20 "os" 21 "strconv" 22 "strings" 23) 24 25// A BuddyInfo is the details parsed from /proc/buddyinfo. 26// The data is comprised of an array of free fragments of each size. 27// The sizes are 2^n*PAGE_SIZE, where n is the array index. 28type BuddyInfo struct { 29 Node string 30 Zone string 31 Sizes []float64 32} 33 34// BuddyInfo reads the buddyinfo statistics from the specified `proc` filesystem. 35func (fs FS) BuddyInfo() ([]BuddyInfo, error) { 36 file, err := os.Open(fs.proc.Path("buddyinfo")) 37 if err != nil { 38 return nil, err 39 } 40 defer file.Close() 41 42 return parseBuddyInfo(file) 43} 44 45func parseBuddyInfo(r io.Reader) ([]BuddyInfo, error) { 46 var ( 47 buddyInfo = []BuddyInfo{} 48 scanner = bufio.NewScanner(r) 49 bucketCount = -1 50 ) 51 52 for scanner.Scan() { 53 var err error 54 line := scanner.Text() 55 parts := strings.Fields(line) 56 57 if len(parts) < 4 { 58 return nil, fmt.Errorf("invalid number of fields when parsing buddyinfo") 59 } 60 61 node := strings.TrimRight(parts[1], ",") 62 zone := strings.TrimRight(parts[3], ",") 63 arraySize := len(parts[4:]) 64 65 if bucketCount == -1 { 66 bucketCount = arraySize 67 } else { 68 if bucketCount != arraySize { 69 return nil, fmt.Errorf("mismatch in number of buddyinfo buckets, previous count %d, new count %d", bucketCount, arraySize) 70 } 71 } 72 73 sizes := make([]float64, arraySize) 74 for i := 0; i < arraySize; i++ { 75 sizes[i], err = strconv.ParseFloat(parts[i+4], 64) 76 if err != nil { 77 return nil, fmt.Errorf("invalid value in buddyinfo: %w", err) 78 } 79 } 80 81 buddyInfo = append(buddyInfo, BuddyInfo{node, zone, sizes}) 82 } 83 84 return buddyInfo, scanner.Err() 85} 86