Remove BPA from Makefile
[icn.git] / cmd / bpa-operator / vendor / github.com / prometheus / procfs / proc_psi.go
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 package procfs
15
16 // The PSI / pressure interface is described at
17 //   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/accounting/psi.txt
18 // Each resource (cpu, io, memory, ...) is exposed as a single file.
19 // Each file may contain up to two lines, one for "some" pressure and one for "full" pressure.
20 // Each line contains several averages (over n seconds) and a total in µs.
21 //
22 // Example io pressure file:
23 // > some avg10=0.06 avg60=0.21 avg300=0.99 total=8537362
24 // > full avg10=0.00 avg60=0.13 avg300=0.96 total=8183134
25
26 import (
27         "fmt"
28         "io"
29         "io/ioutil"
30         "os"
31         "strings"
32 )
33
34 const lineFormat = "avg10=%f avg60=%f avg300=%f total=%d"
35
36 // PSILine is a single line of values as returned by /proc/pressure/*
37 // The Avg entries are averages over n seconds, as a percentage
38 // The Total line is in microseconds
39 type PSILine struct {
40         Avg10  float64
41         Avg60  float64
42         Avg300 float64
43         Total  uint64
44 }
45
46 // PSIStats represent pressure stall information from /proc/pressure/*
47 // Some indicates the share of time in which at least some tasks are stalled
48 // Full indicates the share of time in which all non-idle tasks are stalled simultaneously
49 type PSIStats struct {
50         Some *PSILine
51         Full *PSILine
52 }
53
54 // NewPSIStatsForResource reads pressure stall information for the specified
55 // resource. At time of writing this can be either "cpu", "memory" or "io".
56 func NewPSIStatsForResource(resource string) (PSIStats, error) {
57         fs, err := NewFS(DefaultMountPoint)
58         if err != nil {
59                 return PSIStats{}, err
60         }
61
62         return fs.NewPSIStatsForResource(resource)
63 }
64
65 // NewPSIStatsForResource reads pressure stall information from /proc/pressure/<resource>
66 func (fs FS) NewPSIStatsForResource(resource string) (PSIStats, error) {
67         file, err := os.Open(fs.Path(fmt.Sprintf("%s/%s", "pressure", resource)))
68         if err != nil {
69                 return PSIStats{}, fmt.Errorf("psi_stats: unavailable for %s", resource)
70         }
71
72         defer file.Close()
73         return parsePSIStats(resource, file)
74 }
75
76 // parsePSIStats parses the specified file for pressure stall information
77 func parsePSIStats(resource string, file io.Reader) (PSIStats, error) {
78         psiStats := PSIStats{}
79         stats, err := ioutil.ReadAll(file)
80         if err != nil {
81                 return psiStats, fmt.Errorf("psi_stats: unable to read data for %s", resource)
82         }
83
84         for _, l := range strings.Split(string(stats), "\n") {
85                 prefix := strings.Split(l, " ")[0]
86                 switch prefix {
87                 case "some":
88                         psi := PSILine{}
89                         _, err := fmt.Sscanf(l, fmt.Sprintf("some %s", lineFormat), &psi.Avg10, &psi.Avg60, &psi.Avg300, &psi.Total)
90                         if err != nil {
91                                 return PSIStats{}, err
92                         }
93                         psiStats.Some = &psi
94                 case "full":
95                         psi := PSILine{}
96                         _, err := fmt.Sscanf(l, fmt.Sprintf("full %s", lineFormat), &psi.Avg10, &psi.Avg60, &psi.Avg300, &psi.Total)
97                         if err != nil {
98                                 return PSIStats{}, err
99                         }
100                         psiStats.Full = &psi
101                 default:
102                         // If we encounter a line with an unknown prefix, ignore it and move on
103                         // Should new measurement types be added in the future we'll simply ignore them instead
104                         // of erroring on retrieval
105                         continue
106                 }
107         }
108
109         return psiStats, nil
110 }