Skip to content

Commit

Permalink
Fix seconds reported by schedstat
Browse files Browse the repository at this point in the history
As explained further in the code comments, the previous implementation
was based on incorrect documentation and reported values 10000000 times
too large for the values in seconds.

Furthermore the RunningSeconds() and WaitingSeconds() methods are
removed, as it's not this library's job to interpret these values.

Signed-off-by: Phil Frost <[email protected]>
  • Loading branch information
Phil Frost authored and pgier committed Jul 31, 2019
1 parent 5b594f4 commit 5da962f
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 51 deletions.
42 changes: 16 additions & 26 deletions schedstat.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ var (
// See
// https://www.kernel.org/doc/Documentation/scheduler/sched-stats.txt
// for a detailed description of what these numbers mean.
//
// Note the current kernel documentation claims some of the time units are in
// jiffies when they are actually in nanoseconds since 2.6.23 with the
// introduction of CFS. A fix to the documentation is pending. See
// https://lore.kernel.org/patchwork/project/lkml/list/?series=403473

type Schedstat struct {
CPUs []*SchedstatCPU
}
Expand All @@ -39,16 +45,16 @@ type Schedstat struct {
type SchedstatCPU struct {
CPUNum string

RunningJiffies uint64
WaitingJiffies uint64
RunTimeslices uint64
RunningNanoseconds uint64
WaitingNanoseconds uint64
RunTimeslices uint64
}

// ProcSchedstat contains the values from /proc/<pid>/schedstat
type ProcSchedstat struct {
RunningJiffies uint64
WaitingJiffies uint64
RunTimeslices uint64
RunningNanoseconds uint64
WaitingNanoseconds uint64
RunTimeslices uint64
}

func (fs FS) Schedstat() (*Schedstat, error) {
Expand All @@ -67,12 +73,12 @@ func (fs FS) Schedstat() (*Schedstat, error) {
cpu := &SchedstatCPU{}
cpu.CPUNum = match[1]

cpu.RunningJiffies, err = strconv.ParseUint(match[8], 10, 64)
cpu.RunningNanoseconds, err = strconv.ParseUint(match[8], 10, 64)
if err != nil {
continue
}

cpu.WaitingJiffies, err = strconv.ParseUint(match[9], 10, 64)
cpu.WaitingNanoseconds, err = strconv.ParseUint(match[9], 10, 64)
if err != nil {
continue
}
Expand All @@ -93,12 +99,12 @@ func parseProcSchedstat(contents string) (stats ProcSchedstat, err error) {
match := procLineRE.FindStringSubmatch(contents)

if match != nil {
stats.RunningJiffies, err = strconv.ParseUint(match[1], 10, 64)
stats.RunningNanoseconds, err = strconv.ParseUint(match[1], 10, 64)
if err != nil {
return
}

stats.WaitingJiffies, err = strconv.ParseUint(match[2], 10, 64)
stats.WaitingNanoseconds, err = strconv.ParseUint(match[2], 10, 64)
if err != nil {
return
}
Expand All @@ -110,19 +116,3 @@ func parseProcSchedstat(contents string) (stats ProcSchedstat, err error) {
err = errors.New("could not parse schedstat")
return
}

func (stat *SchedstatCPU) RunningSeconds() float64 {
return float64(stat.RunningJiffies) / userHZ
}

func (stat *SchedstatCPU) WaitingSeconds() float64 {
return float64(stat.WaitingJiffies) / userHZ
}

func (stat *ProcSchedstat) RunningSeconds() float64 {
return float64(stat.RunningJiffies) / userHZ
}

func (stat *ProcSchedstat) WaitingSeconds() float64 {
return float64(stat.WaitingJiffies) / userHZ
}
40 changes: 15 additions & 25 deletions schedstat_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@

package procfs

import "testing"
import (
"testing"
)

func TestSchedstat(t *testing.T) {
stats, err := getProcFixtures(t).Schedstat()
Expand All @@ -36,18 +38,12 @@ func TestSchedstat(t *testing.T) {
t.Error("could not find cpu0")
}

if want, have := uint64(2045936778163039), cpu.RunningJiffies; want != have {
t.Errorf("want RunningJiffies %v, have %v", want, have)
}
if want, have := float64(2045936778163039)/userHZ, cpu.RunningSeconds(); want != have {
t.Errorf("want RunningSeconds() %v, have %v", want, have)
if want, have := uint64(2045936778163039), cpu.RunningNanoseconds; want != have {
t.Errorf("want RunningNanoseconds %v, have %v", want, have)
}

if want, have := uint64(343796328169361), cpu.WaitingJiffies; want != have {
t.Errorf("want WaitingJiffies %v, have %v", want, have)
}
if want, have := float64(343796328169361)/userHZ, cpu.WaitingSeconds(); want != have {
t.Errorf("want WaitingSeconds() %v, have %v", want, have)
if want, have := uint64(343796328169361), cpu.WaitingNanoseconds; want != have {
t.Errorf("want WaitingNanoseconds %v, have %v", want, have)
}

if want, have := uint64(4767485306), cpu.RunTimeslices; want != have {
Expand All @@ -66,18 +62,12 @@ func TestProcSchedstat(t *testing.T) {
t.Fatal(err)
}

if want, have := uint64(411605849), schedstat.RunningJiffies; want != have {
t.Errorf("want RunningJiffies %v, have %v", want, have)
}
if want, have := float64(411605849)/userHZ, schedstat.RunningSeconds(); want != have {
t.Errorf("want RunningSeconds() %v, have %v", want, have)
if want, have := uint64(411605849), schedstat.RunningNanoseconds; want != have {
t.Errorf("want RunningNanoseconds %v, have %v", want, have)
}

if want, have := uint64(93680043), schedstat.WaitingJiffies; want != have {
t.Errorf("want WaitingJiffies %v, have %v", want, have)
}
if want, have := float64(93680043)/userHZ, schedstat.WaitingSeconds(); want != have {
t.Errorf("want WaitingSeconds() %v, have %v", want, have)
if want, have := uint64(93680043), schedstat.WaitingNanoseconds; want != have {
t.Errorf("want WaitingNanoseconds %v, have %v", want, have)
}

if want, have := uint64(79), schedstat.RunTimeslices; want != have {
Expand Down Expand Up @@ -113,11 +103,11 @@ func TestProcSchedstatMultipleLines(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if want, have := uint64(123), schedstat.RunningJiffies; want != have {
t.Errorf("want RunningJiffies %v, have %v", want, have)
if want, have := uint64(123), schedstat.RunningNanoseconds; want != have {
t.Errorf("want RunningNanoseconds %v, have %v", want, have)
}
if want, have := uint64(456), schedstat.WaitingJiffies; want != have {
t.Errorf("want WaitingJiffies %v, have %v", want, have)
if want, have := uint64(456), schedstat.WaitingNanoseconds; want != have {
t.Errorf("want WaitingNanoseconds %v, have %v", want, have)
}
if want, have := uint64(789), schedstat.RunTimeslices; want != have {
t.Errorf("want RunTimeslices %v, have %v", want, have)
Expand Down

0 comments on commit 5da962f

Please sign in to comment.