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 14package procfs 15 16import ( 17 "bufio" 18 "errors" 19 "os" 20 "regexp" 21 "strconv" 22) 23 24var ( 25 cpuLineRE = regexp.MustCompile(`cpu(\d+) (\d+) (\d+) (\d+) (\d+) (\d+) (\d+) (\d+) (\d+) (\d+)`) 26 procLineRE = regexp.MustCompile(`(\d+) (\d+) (\d+)`) 27) 28 29// Schedstat contains scheduler statistics from /proc/schedstat 30// 31// See 32// https://www.kernel.org/doc/Documentation/scheduler/sched-stats.txt 33// for a detailed description of what these numbers mean. 34// 35// Note the current kernel documentation claims some of the time units are in 36// jiffies when they are actually in nanoseconds since 2.6.23 with the 37// introduction of CFS. A fix to the documentation is pending. See 38// https://lore.kernel.org/patchwork/project/lkml/list/?series=403473 39type Schedstat struct { 40 CPUs []*SchedstatCPU 41} 42 43// SchedstatCPU contains the values from one "cpu<N>" line 44type SchedstatCPU struct { 45 CPUNum string 46 47 RunningNanoseconds uint64 48 WaitingNanoseconds uint64 49 RunTimeslices uint64 50} 51 52// ProcSchedstat contains the values from /proc/<pid>/schedstat 53type ProcSchedstat struct { 54 RunningNanoseconds uint64 55 WaitingNanoseconds uint64 56 RunTimeslices uint64 57} 58 59// Schedstat reads data from /proc/schedstat 60func (fs FS) Schedstat() (*Schedstat, error) { 61 file, err := os.Open(fs.proc.Path("schedstat")) 62 if err != nil { 63 return nil, err 64 } 65 defer file.Close() 66 67 stats := &Schedstat{} 68 scanner := bufio.NewScanner(file) 69 70 for scanner.Scan() { 71 match := cpuLineRE.FindStringSubmatch(scanner.Text()) 72 if match != nil { 73 cpu := &SchedstatCPU{} 74 cpu.CPUNum = match[1] 75 76 cpu.RunningNanoseconds, err = strconv.ParseUint(match[8], 10, 64) 77 if err != nil { 78 continue 79 } 80 81 cpu.WaitingNanoseconds, err = strconv.ParseUint(match[9], 10, 64) 82 if err != nil { 83 continue 84 } 85 86 cpu.RunTimeslices, err = strconv.ParseUint(match[10], 10, 64) 87 if err != nil { 88 continue 89 } 90 91 stats.CPUs = append(stats.CPUs, cpu) 92 } 93 } 94 95 return stats, nil 96} 97 98func parseProcSchedstat(contents string) (ProcSchedstat, error) { 99 var ( 100 stats ProcSchedstat 101 err error 102 ) 103 match := procLineRE.FindStringSubmatch(contents) 104 105 if match != nil { 106 stats.RunningNanoseconds, err = strconv.ParseUint(match[1], 10, 64) 107 if err != nil { 108 return stats, err 109 } 110 111 stats.WaitingNanoseconds, err = strconv.ParseUint(match[2], 10, 64) 112 if err != nil { 113 return stats, err 114 } 115 116 stats.RunTimeslices, err = strconv.ParseUint(match[3], 10, 64) 117 return stats, err 118 } 119 120 return stats, errors.New("could not parse schedstat") 121} 122