buddyinfo.go 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  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. package procfs
  14. import (
  15. "bufio"
  16. "fmt"
  17. "io"
  18. "os"
  19. "strconv"
  20. "strings"
  21. )
  22. // A BuddyInfo is the details parsed from /proc/buddyinfo.
  23. // The data is comprised of an array of free fragments of each size.
  24. // The sizes are 2^n*PAGE_SIZE, where n is the array index.
  25. type BuddyInfo struct {
  26. Node string
  27. Zone string
  28. Sizes []float64
  29. }
  30. // BuddyInfo reads the buddyinfo statistics from the specified `proc` filesystem.
  31. func (fs FS) BuddyInfo() ([]BuddyInfo, error) {
  32. file, err := os.Open(fs.proc.Path("buddyinfo"))
  33. if err != nil {
  34. return nil, err
  35. }
  36. defer file.Close()
  37. return parseBuddyInfo(file)
  38. }
  39. func parseBuddyInfo(r io.Reader) ([]BuddyInfo, error) {
  40. var (
  41. buddyInfo = []BuddyInfo{}
  42. scanner = bufio.NewScanner(r)
  43. bucketCount = -1
  44. )
  45. for scanner.Scan() {
  46. var err error
  47. line := scanner.Text()
  48. parts := strings.Fields(line)
  49. if len(parts) < 4 {
  50. return nil, fmt.Errorf("%w: Invalid number of fields, found: %v", ErrFileParse, parts)
  51. }
  52. node := strings.TrimRight(parts[1], ",")
  53. zone := strings.TrimRight(parts[3], ",")
  54. arraySize := len(parts[4:])
  55. if bucketCount == -1 {
  56. bucketCount = arraySize
  57. } else {
  58. if bucketCount != arraySize {
  59. return nil, fmt.Errorf("%w: mismatch in number of buddyinfo buckets, previous count %d, new count %d", ErrFileParse, bucketCount, arraySize)
  60. }
  61. }
  62. sizes := make([]float64, arraySize)
  63. for i := 0; i < arraySize; i++ {
  64. sizes[i], err = strconv.ParseFloat(parts[i+4], 64)
  65. if err != nil {
  66. return nil, fmt.Errorf("%s: Invalid valid in buddyinfo: %f: %w", ErrFileParse, sizes[i], err)
  67. }
  68. }
  69. buddyInfo = append(buddyInfo, BuddyInfo{node, zone, sizes})
  70. }
  71. return buddyInfo, scanner.Err()
  72. }