2021-02-01 00:10:16 +01:00
|
|
|
// Copyright 2019 The Prometheus Authors
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
// +build !windows
|
|
|
|
|
|
|
|
package procfs
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"regexp"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/prometheus/procfs/internal/util"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Zoneinfo holds info parsed from /proc/zoneinfo.
|
|
|
|
type Zoneinfo struct {
|
|
|
|
Node string
|
|
|
|
Zone string
|
|
|
|
NrFreePages *int64
|
|
|
|
Min *int64
|
|
|
|
Low *int64
|
|
|
|
High *int64
|
|
|
|
Scanned *int64
|
|
|
|
Spanned *int64
|
|
|
|
Present *int64
|
|
|
|
Managed *int64
|
|
|
|
NrActiveAnon *int64
|
|
|
|
NrInactiveAnon *int64
|
|
|
|
NrIsolatedAnon *int64
|
|
|
|
NrAnonPages *int64
|
|
|
|
NrAnonTransparentHugepages *int64
|
|
|
|
NrActiveFile *int64
|
|
|
|
NrInactiveFile *int64
|
|
|
|
NrIsolatedFile *int64
|
|
|
|
NrFilePages *int64
|
|
|
|
NrSlabReclaimable *int64
|
|
|
|
NrSlabUnreclaimable *int64
|
|
|
|
NrMlockStack *int64
|
|
|
|
NrKernelStack *int64
|
|
|
|
NrMapped *int64
|
|
|
|
NrDirty *int64
|
|
|
|
NrWriteback *int64
|
|
|
|
NrUnevictable *int64
|
|
|
|
NrShmem *int64
|
|
|
|
NrDirtied *int64
|
|
|
|
NrWritten *int64
|
|
|
|
NumaHit *int64
|
|
|
|
NumaMiss *int64
|
|
|
|
NumaForeign *int64
|
|
|
|
NumaInterleave *int64
|
|
|
|
NumaLocal *int64
|
|
|
|
NumaOther *int64
|
|
|
|
Protection []*int64
|
|
|
|
}
|
|
|
|
|
|
|
|
var nodeZoneRE = regexp.MustCompile(`(\d+), zone\s+(\w+)`)
|
|
|
|
|
|
|
|
// Zoneinfo parses an zoneinfo-file (/proc/zoneinfo) and returns a slice of
|
|
|
|
// structs containing the relevant info. More information available here:
|
|
|
|
// https://www.kernel.org/doc/Documentation/sysctl/vm.txt
|
|
|
|
func (fs FS) Zoneinfo() ([]Zoneinfo, error) {
|
|
|
|
data, err := ioutil.ReadFile(fs.proc.Path("zoneinfo"))
|
|
|
|
if err != nil {
|
2021-02-16 21:24:44 +01:00
|
|
|
return nil, fmt.Errorf("error reading zoneinfo %q: %w", fs.proc.Path("zoneinfo"), err)
|
2021-02-01 00:10:16 +01:00
|
|
|
}
|
|
|
|
zoneinfo, err := parseZoneinfo(data)
|
|
|
|
if err != nil {
|
2021-02-16 21:24:44 +01:00
|
|
|
return nil, fmt.Errorf("error parsing zoneinfo %q: %w", fs.proc.Path("zoneinfo"), err)
|
2021-02-01 00:10:16 +01:00
|
|
|
}
|
|
|
|
return zoneinfo, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func parseZoneinfo(zoneinfoData []byte) ([]Zoneinfo, error) {
|
|
|
|
|
|
|
|
zoneinfo := []Zoneinfo{}
|
|
|
|
|
|
|
|
zoneinfoBlocks := bytes.Split(zoneinfoData, []byte("\nNode"))
|
|
|
|
for _, block := range zoneinfoBlocks {
|
|
|
|
var zoneinfoElement Zoneinfo
|
|
|
|
lines := strings.Split(string(block), "\n")
|
|
|
|
for _, line := range lines {
|
|
|
|
|
|
|
|
if nodeZone := nodeZoneRE.FindStringSubmatch(line); nodeZone != nil {
|
|
|
|
zoneinfoElement.Node = nodeZone[1]
|
|
|
|
zoneinfoElement.Zone = nodeZone[2]
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if strings.HasPrefix(strings.TrimSpace(line), "per-node stats") {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
parts := strings.Fields(strings.TrimSpace(line))
|
|
|
|
if len(parts) < 2 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
vp := util.NewValueParser(parts[1])
|
|
|
|
switch parts[0] {
|
|
|
|
case "nr_free_pages":
|
|
|
|
zoneinfoElement.NrFreePages = vp.PInt64()
|
|
|
|
case "min":
|
|
|
|
zoneinfoElement.Min = vp.PInt64()
|
|
|
|
case "low":
|
|
|
|
zoneinfoElement.Low = vp.PInt64()
|
|
|
|
case "high":
|
|
|
|
zoneinfoElement.High = vp.PInt64()
|
|
|
|
case "scanned":
|
|
|
|
zoneinfoElement.Scanned = vp.PInt64()
|
|
|
|
case "spanned":
|
|
|
|
zoneinfoElement.Spanned = vp.PInt64()
|
|
|
|
case "present":
|
|
|
|
zoneinfoElement.Present = vp.PInt64()
|
|
|
|
case "managed":
|
|
|
|
zoneinfoElement.Managed = vp.PInt64()
|
|
|
|
case "nr_active_anon":
|
|
|
|
zoneinfoElement.NrActiveAnon = vp.PInt64()
|
|
|
|
case "nr_inactive_anon":
|
|
|
|
zoneinfoElement.NrInactiveAnon = vp.PInt64()
|
|
|
|
case "nr_isolated_anon":
|
|
|
|
zoneinfoElement.NrIsolatedAnon = vp.PInt64()
|
|
|
|
case "nr_anon_pages":
|
|
|
|
zoneinfoElement.NrAnonPages = vp.PInt64()
|
|
|
|
case "nr_anon_transparent_hugepages":
|
|
|
|
zoneinfoElement.NrAnonTransparentHugepages = vp.PInt64()
|
|
|
|
case "nr_active_file":
|
|
|
|
zoneinfoElement.NrActiveFile = vp.PInt64()
|
|
|
|
case "nr_inactive_file":
|
|
|
|
zoneinfoElement.NrInactiveFile = vp.PInt64()
|
|
|
|
case "nr_isolated_file":
|
|
|
|
zoneinfoElement.NrIsolatedFile = vp.PInt64()
|
|
|
|
case "nr_file_pages":
|
|
|
|
zoneinfoElement.NrFilePages = vp.PInt64()
|
|
|
|
case "nr_slab_reclaimable":
|
|
|
|
zoneinfoElement.NrSlabReclaimable = vp.PInt64()
|
|
|
|
case "nr_slab_unreclaimable":
|
|
|
|
zoneinfoElement.NrSlabUnreclaimable = vp.PInt64()
|
|
|
|
case "nr_mlock_stack":
|
|
|
|
zoneinfoElement.NrMlockStack = vp.PInt64()
|
|
|
|
case "nr_kernel_stack":
|
|
|
|
zoneinfoElement.NrKernelStack = vp.PInt64()
|
|
|
|
case "nr_mapped":
|
|
|
|
zoneinfoElement.NrMapped = vp.PInt64()
|
|
|
|
case "nr_dirty":
|
|
|
|
zoneinfoElement.NrDirty = vp.PInt64()
|
|
|
|
case "nr_writeback":
|
|
|
|
zoneinfoElement.NrWriteback = vp.PInt64()
|
|
|
|
case "nr_unevictable":
|
|
|
|
zoneinfoElement.NrUnevictable = vp.PInt64()
|
|
|
|
case "nr_shmem":
|
|
|
|
zoneinfoElement.NrShmem = vp.PInt64()
|
|
|
|
case "nr_dirtied":
|
|
|
|
zoneinfoElement.NrDirtied = vp.PInt64()
|
|
|
|
case "nr_written":
|
|
|
|
zoneinfoElement.NrWritten = vp.PInt64()
|
|
|
|
case "numa_hit":
|
|
|
|
zoneinfoElement.NumaHit = vp.PInt64()
|
|
|
|
case "numa_miss":
|
|
|
|
zoneinfoElement.NumaMiss = vp.PInt64()
|
|
|
|
case "numa_foreign":
|
|
|
|
zoneinfoElement.NumaForeign = vp.PInt64()
|
|
|
|
case "numa_interleave":
|
|
|
|
zoneinfoElement.NumaInterleave = vp.PInt64()
|
|
|
|
case "numa_local":
|
|
|
|
zoneinfoElement.NumaLocal = vp.PInt64()
|
|
|
|
case "numa_other":
|
|
|
|
zoneinfoElement.NumaOther = vp.PInt64()
|
|
|
|
case "protection:":
|
|
|
|
protectionParts := strings.Split(line, ":")
|
|
|
|
protectionValues := strings.Replace(protectionParts[1], "(", "", 1)
|
|
|
|
protectionValues = strings.Replace(protectionValues, ")", "", 1)
|
|
|
|
protectionValues = strings.TrimSpace(protectionValues)
|
|
|
|
protectionStringMap := strings.Split(protectionValues, ", ")
|
|
|
|
val, err := util.ParsePInt64s(protectionStringMap)
|
|
|
|
if err == nil {
|
|
|
|
zoneinfoElement.Protection = val
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
zoneinfo = append(zoneinfo, zoneinfoElement)
|
|
|
|
}
|
|
|
|
return zoneinfo, nil
|
|
|
|
}
|