1// Copyright 2019 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 14// +build !windows 15 16package procfs 17 18import ( 19 "bytes" 20 "fmt" 21 "io/ioutil" 22 "regexp" 23 "strings" 24 25 "github.com/prometheus/procfs/internal/util" 26) 27 28// Zoneinfo holds info parsed from /proc/zoneinfo. 29type Zoneinfo struct { 30 Node string 31 Zone string 32 NrFreePages *int64 33 Min *int64 34 Low *int64 35 High *int64 36 Scanned *int64 37 Spanned *int64 38 Present *int64 39 Managed *int64 40 NrActiveAnon *int64 41 NrInactiveAnon *int64 42 NrIsolatedAnon *int64 43 NrAnonPages *int64 44 NrAnonTransparentHugepages *int64 45 NrActiveFile *int64 46 NrInactiveFile *int64 47 NrIsolatedFile *int64 48 NrFilePages *int64 49 NrSlabReclaimable *int64 50 NrSlabUnreclaimable *int64 51 NrMlockStack *int64 52 NrKernelStack *int64 53 NrMapped *int64 54 NrDirty *int64 55 NrWriteback *int64 56 NrUnevictable *int64 57 NrShmem *int64 58 NrDirtied *int64 59 NrWritten *int64 60 NumaHit *int64 61 NumaMiss *int64 62 NumaForeign *int64 63 NumaInterleave *int64 64 NumaLocal *int64 65 NumaOther *int64 66 Protection []*int64 67} 68 69var nodeZoneRE = regexp.MustCompile(`(\d+), zone\s+(\w+)`) 70 71// Zoneinfo parses an zoneinfo-file (/proc/zoneinfo) and returns a slice of 72// structs containing the relevant info. More information available here: 73// https://www.kernel.org/doc/Documentation/sysctl/vm.txt 74func (fs FS) Zoneinfo() ([]Zoneinfo, error) { 75 data, err := ioutil.ReadFile(fs.proc.Path("zoneinfo")) 76 if err != nil { 77 return nil, fmt.Errorf("error reading zoneinfo %q: %w", fs.proc.Path("zoneinfo"), err) 78 } 79 zoneinfo, err := parseZoneinfo(data) 80 if err != nil { 81 return nil, fmt.Errorf("error parsing zoneinfo %q: %w", fs.proc.Path("zoneinfo"), err) 82 } 83 return zoneinfo, nil 84} 85 86func parseZoneinfo(zoneinfoData []byte) ([]Zoneinfo, error) { 87 88 zoneinfo := []Zoneinfo{} 89 90 zoneinfoBlocks := bytes.Split(zoneinfoData, []byte("\nNode")) 91 for _, block := range zoneinfoBlocks { 92 var zoneinfoElement Zoneinfo 93 lines := strings.Split(string(block), "\n") 94 for _, line := range lines { 95 96 if nodeZone := nodeZoneRE.FindStringSubmatch(line); nodeZone != nil { 97 zoneinfoElement.Node = nodeZone[1] 98 zoneinfoElement.Zone = nodeZone[2] 99 continue 100 } 101 if strings.HasPrefix(strings.TrimSpace(line), "per-node stats") { 102 zoneinfoElement.Zone = "" 103 continue 104 } 105 parts := strings.Fields(strings.TrimSpace(line)) 106 if len(parts) < 2 { 107 continue 108 } 109 vp := util.NewValueParser(parts[1]) 110 switch parts[0] { 111 case "nr_free_pages": 112 zoneinfoElement.NrFreePages = vp.PInt64() 113 case "min": 114 zoneinfoElement.Min = vp.PInt64() 115 case "low": 116 zoneinfoElement.Low = vp.PInt64() 117 case "high": 118 zoneinfoElement.High = vp.PInt64() 119 case "scanned": 120 zoneinfoElement.Scanned = vp.PInt64() 121 case "spanned": 122 zoneinfoElement.Spanned = vp.PInt64() 123 case "present": 124 zoneinfoElement.Present = vp.PInt64() 125 case "managed": 126 zoneinfoElement.Managed = vp.PInt64() 127 case "nr_active_anon": 128 zoneinfoElement.NrActiveAnon = vp.PInt64() 129 case "nr_inactive_anon": 130 zoneinfoElement.NrInactiveAnon = vp.PInt64() 131 case "nr_isolated_anon": 132 zoneinfoElement.NrIsolatedAnon = vp.PInt64() 133 case "nr_anon_pages": 134 zoneinfoElement.NrAnonPages = vp.PInt64() 135 case "nr_anon_transparent_hugepages": 136 zoneinfoElement.NrAnonTransparentHugepages = vp.PInt64() 137 case "nr_active_file": 138 zoneinfoElement.NrActiveFile = vp.PInt64() 139 case "nr_inactive_file": 140 zoneinfoElement.NrInactiveFile = vp.PInt64() 141 case "nr_isolated_file": 142 zoneinfoElement.NrIsolatedFile = vp.PInt64() 143 case "nr_file_pages": 144 zoneinfoElement.NrFilePages = vp.PInt64() 145 case "nr_slab_reclaimable": 146 zoneinfoElement.NrSlabReclaimable = vp.PInt64() 147 case "nr_slab_unreclaimable": 148 zoneinfoElement.NrSlabUnreclaimable = vp.PInt64() 149 case "nr_mlock_stack": 150 zoneinfoElement.NrMlockStack = vp.PInt64() 151 case "nr_kernel_stack": 152 zoneinfoElement.NrKernelStack = vp.PInt64() 153 case "nr_mapped": 154 zoneinfoElement.NrMapped = vp.PInt64() 155 case "nr_dirty": 156 zoneinfoElement.NrDirty = vp.PInt64() 157 case "nr_writeback": 158 zoneinfoElement.NrWriteback = vp.PInt64() 159 case "nr_unevictable": 160 zoneinfoElement.NrUnevictable = vp.PInt64() 161 case "nr_shmem": 162 zoneinfoElement.NrShmem = vp.PInt64() 163 case "nr_dirtied": 164 zoneinfoElement.NrDirtied = vp.PInt64() 165 case "nr_written": 166 zoneinfoElement.NrWritten = vp.PInt64() 167 case "numa_hit": 168 zoneinfoElement.NumaHit = vp.PInt64() 169 case "numa_miss": 170 zoneinfoElement.NumaMiss = vp.PInt64() 171 case "numa_foreign": 172 zoneinfoElement.NumaForeign = vp.PInt64() 173 case "numa_interleave": 174 zoneinfoElement.NumaInterleave = vp.PInt64() 175 case "numa_local": 176 zoneinfoElement.NumaLocal = vp.PInt64() 177 case "numa_other": 178 zoneinfoElement.NumaOther = vp.PInt64() 179 case "protection:": 180 protectionParts := strings.Split(line, ":") 181 protectionValues := strings.Replace(protectionParts[1], "(", "", 1) 182 protectionValues = strings.Replace(protectionValues, ")", "", 1) 183 protectionValues = strings.TrimSpace(protectionValues) 184 protectionStringMap := strings.Split(protectionValues, ", ") 185 val, err := util.ParsePInt64s(protectionStringMap) 186 if err == nil { 187 zoneinfoElement.Protection = val 188 } 189 } 190 191 } 192 193 zoneinfo = append(zoneinfo, zoneinfoElement) 194 } 195 return zoneinfo, nil 196} 197