Skip to content

Commit

Permalink
Added general file descriptor logic and implemented for linux
Browse files Browse the repository at this point in the history
  • Loading branch information
kinghrothgar committed May 31, 2016
1 parent e9bc408 commit 70932cd
Show file tree
Hide file tree
Showing 8 changed files with 205 additions and 0 deletions.
6 changes: 6 additions & 0 deletions concrete_sigar.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,9 @@ func (c *ConcreteSigar) GetFileSystemUsage(path string) (FileSystemUsage, error)
err := f.Get(path)
return f, err
}

func (c *ConcreteSigar) GetFDUsage() (FDUsage, error) {
fd := FDUsage{}
err := fd.Get()
return fd, err
}
15 changes: 15 additions & 0 deletions concrete_sigar_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,18 @@ func TestConcreteFileSystemUsage(t *testing.T) {
fsusage, err = concreteSigar.GetFileSystemUsage("T O T A L L Y B O G U S")
assert.Error(t, err)
}

func TestConcreteGetFDUsage(t *testing.T) {
concreteSigar := &sigar.ConcreteSigar{}
fdUsage, err := concreteSigar.GetFDUsage()
// if it's not implemented, don't test
if _, ok := err.(*sigar.ErrNotImplemented); ok {
println("Skipping *ConcreteSigar.GetFDUsage test because it is no implemented for " + runtime.GOOS)
return
}
if assert.NoError(t, err) {
assert.True(t, fdUsage.Open > 0)
assert.True(t, fdUsage.Open <= fdUsage.Max)
println("Testing fdUsage")
}
}
9 changes: 9 additions & 0 deletions sigar_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"fmt"
"io"
"os/user"
"runtime"
"strconv"
"syscall"
"time"
Expand Down Expand Up @@ -164,6 +165,10 @@ func (self *CpuList) Get() error {
return nil
}

func (self *FDUsage) Get() error {
return &ErrNotImplemented{"not implemented for " + runtime.GOOS}
}

func (self *FileSystemList) Get() error {
num, err := syscall.Getfsstat(nil, C.MNT_NOWAIT)
if err != nil {
Expand Down Expand Up @@ -329,6 +334,10 @@ func (self *ProcExe) Get(pid int) error {
return kern_procargs(pid, exe, nil, nil)
}

func (self *ProcFDUsage) Get(pid int) error {
return &ErrNotImplemented{"not implemented for " + runtime.GOOS}
}

// wrapper around sysctl KERN_PROCARGS2
// callbacks params are optional,
// up to the caller as to which pieces of data they want
Expand Down
21 changes: 21 additions & 0 deletions sigar_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ type Sigar interface {
GetMem() (Mem, error)
GetSwap() (Swap, error)
GetFileSystemUsage(string) (FileSystemUsage, error)
GetFDUsage() (FDUsage, error)
}

type ErrNotImplemented struct {
msg string
}

func (e ErrNotImplemented) Error() string {
return e.msg
}

type Cpu struct {
Expand Down Expand Up @@ -67,6 +76,12 @@ type CpuList struct {
List []Cpu
}

type FDUsage struct {
Open uint64
Unused uint64
Max uint64
}

type FileSystem struct {
DirName string
DevName string
Expand Down Expand Up @@ -141,3 +156,9 @@ type ProcExe struct {
Cwd string
Root string
}

type ProcFDUsage struct {
Open uint64
SoftLimit uint64
HardLimit uint64
}
35 changes: 35 additions & 0 deletions sigar_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,18 @@ func (self *FileSystemList) Get() error {
return err
}

func (self *FDUsage) Get() error {
return readFile(Procd+"/sys/fs/file-nr", func(line string) bool {
fields := strings.Fields(line)
if len(fields) == 3 {
self.Open, _ = strconv.ParseUint(fields[0], 10, 64)
self.Unused, _ = strconv.ParseUint(fields[1], 10, 64)
self.Max, _ = strconv.ParseUint(fields[2], 10, 64)
}
return false
})
}

func (self *ProcList) Get() error {
dir, err := os.Open(Procd)
if err != nil {
Expand Down Expand Up @@ -339,6 +351,29 @@ func (self *ProcExe) Get(pid int) error {
return nil
}

func (self *ProcFDUsage) Get(pid int) error {
err := readFile(procFileName(pid, "limits"), func(line string) bool {
if strings.HasPrefix(line, "Max open files") {
fields := strings.Fields(line)
if len(fields) == 6 {
self.SoftLimit, _ = strconv.ParseUint(fields[3], 10, 64)
self.HardLimit, _ = strconv.ParseUint(fields[4], 10, 64)
}
return false
}
return true
})
if err != nil {
return err
}
fds, err := ioutil.ReadDir(procFileName(pid, "fd"))
if err != nil {
return err
}
self.Open = uint64(len(fds))
return nil
}

func parseMeminfo(table map[string]*uint64) error {
return readFile(Procd+"/meminfo", func(line string) bool {
fields := strings.Split(line, ":")
Expand Down
101 changes: 101 additions & 0 deletions sigar_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,107 @@ DirectMap2M: 333824 kB
}
}

func TestFDUsage(t *testing.T) {
setUp(t)
defer tearDown(t)

// There is no Uint63 until 2.0
open := uint64(rand.Uint32())
unused := uint64(rand.Uint32())
max := uint64(rand.Uint32())
fileNRContents := fmt.Sprintf("%d %d %d", open, unused, max)

fileNRPath := procd + "/sys/fs"
os.MkdirAll(fileNRPath, 0755)
fileNRFile := fileNRPath + "/file-nr"
err := ioutil.WriteFile(fileNRFile, []byte(fileNRContents), 0444)
if err != nil {
t.Fatal(err)
}

fd := sigar.FDUsage{}
if assert.NoError(t, fd.Get()) {
assert.Equal(t, open, fd.Open)
assert.Equal(t, unused, fd.Unused)
assert.Equal(t, max, fd.Max)
}
}

func TestProcFDUsage(t *testing.T) {
setUp(t)
defer tearDown(t)

pid := rand.Intn(32768)
pidDir := fmt.Sprintf("%s/%d", procd, pid)
err := os.Mkdir(pidDir, 0755)
if err != nil {
t.Fatal(err)
}
soft := uint64(rand.Uint32())
// subtract to prevent the posibility of overflow
if soft != 0 {
soft -= 1
}
// max sure hard is always bigger than soft
hard := soft + uint64(rand.Uint32())

limitsContents := `Limit Soft Limit Hard Limit Units
Max cpu time unlimited unlimited seconds
Max file size unlimited unlimited bytes
Max data size unlimited unlimited bytes
Max stack size 8388608 unlimited bytes
Max core file size 0 unlimited bytes
Max resident set unlimited unlimited bytes
Max processes 29875 29875 processes
Max open files %d %d files
Max locked memory 65536 65536 bytes
Max address space unlimited unlimited bytes
Max file locks unlimited unlimited locks
Max pending signals 29875 29875 signals
Max msgqueue size 819200 819200 bytes
Max nice priority 0 0
Max realtime priority 0 0
Max realtime timeout unlimited unlimited us
`

limitsContents = fmt.Sprintf(limitsContents, soft, hard)

limitsFile := pidDir + "/limits"
err = ioutil.WriteFile(limitsFile, []byte(limitsContents), 0444)
if err != nil {
t.Fatal(err)
}
open := rand.Intn(32768)
if err = writeFDs(pid, open); err != nil {
t.Fatal(err)
}

procFD := sigar.ProcFDUsage{}
if assert.NoError(t, procFD.Get(pid)) {
assert.Equal(t, uint64(open), procFD.Open)
assert.Equal(t, soft, procFD.SoftLimit)
assert.Equal(t, hard, procFD.HardLimit)
}
}

func writeFDs(pid int, count int) error {
fdDir := fmt.Sprintf("%s/%d/fd", procd, pid)
err := os.Mkdir(fdDir, 0755)
if err != nil {
return err
}

for i := 0; i < count; i++ {
fdPath := fmt.Sprintf("%s/%d", fdDir, i)
f, err := os.Create(fdPath)
if err != nil {
return err
}
f.Close()
}
return nil
}

func writePidStats(pid int, procName string, path string) error {
stats := "S 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 " +
"20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 " +
Expand Down
9 changes: 9 additions & 0 deletions sigar_openbsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import "C"
//import "github.com/davecgh/go-spew/spew"

import (
"runtime"
"syscall"
"time"
"unsafe"
Expand Down Expand Up @@ -187,6 +188,10 @@ func (self *FileSystemUsage) Get(path string) error {
return nil
}

func (self *FDUsage) Get() error {
return &ErrNotImplemented{"not implemented for " + runtime.GOOS}
}

func (self *LoadAverage) Get() error {
avg := []C.double{0, 0, 0}

Expand Down Expand Up @@ -368,6 +373,10 @@ func (self *ProcExe) Get(pid int) error {
return nil
}

func (self *ProcFDUsage) Get(pid int) error {
return &ErrNotImplemented{"not implemented for " + runtime.GOOS}
}

func fillCpu(cpu *Cpu, load [C.CPUSTATES]C.long) {
cpu.User = uint64(load[0])
cpu.Nice = uint64(load[1])
Expand Down
9 changes: 9 additions & 0 deletions sigar_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"fmt"
"os"
"path/filepath"
"runtime"
"syscall"
"time"
"unsafe"
Expand Down Expand Up @@ -209,6 +210,10 @@ func (self *FileSystemList) Get() error {
return nil
}

func (self *FDUsage) Get() error {
return &ErrNotImplemented{"not implemented for " + runtime.GOOS}
}

// Retrieves the process identifier for each process object in the system.

func (self *ProcList) Get() error {
Expand Down Expand Up @@ -466,6 +471,10 @@ func (self *ProcExe) Get(pid int) error {
return notImplemented()
}

func (self *ProcFDUsage) Get(pid int) error {
return &ErrNotImplemented{"not implemented for " + runtime.GOOS}
}

func (self *FileSystemUsage) Get(path string) error {

/*
Expand Down

0 comments on commit 70932cd

Please sign in to comment.