From de2155df7c09f2f464964c06537e82b39ce5a423 Mon Sep 17 00:00:00 2001 From: "Paul Buetow (europa)" Date: Sun, 31 May 2015 11:06:43 +0100 Subject: rename to gotop --- Makefile | 6 +- README.md | 4 +- diskstats/diskstats.go | 2 +- gotop/main.go | 247 +++++++++++++++++++++++++++++++++++++++++++++++++ gstat/main.go | 247 ------------------------------------------------- process/process.go | 2 +- 6 files changed, 254 insertions(+), 254 deletions(-) create mode 100644 gotop/main.go delete mode 100644 gstat/main.go diff --git a/Makefile b/Makefile index e6a23bc..218bd53 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ install: - go install github.com/buetow/gstat/gstat + go install github.com/buetow/gotop/gotop run: - go run gstat/main.go + go run gotop/main.go docu: install - sh -c '($(GOPATH)/bin/gstat -h 2>&1)|sed 1d > help.txt;exit 0' + sh -c '($(GOPATH)/bin/gotop -h 2>&1)|sed 1d > help.txt;exit 0' diff --git a/README.md b/README.md index 3476c0e..dfbd1f6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -gstat +gotop ===== An iotop replacement programmed in Go for Linux -See http://gstat.buetow.org for more information. +See http://gotop.buetow.org for more information. diff --git a/diskstats/diskstats.go b/diskstats/diskstats.go index 190e56c..7f75f92 100644 --- a/diskstats/diskstats.go +++ b/diskstats/diskstats.go @@ -2,7 +2,7 @@ package diskstats import ( "fmt" - "github.com/buetow/gstat/utils" + "github.com/buetow/gotop/utils" ) type Diskstats struct { diff --git a/gotop/main.go b/gotop/main.go new file mode 100644 index 0000000..5ed6331 --- /dev/null +++ b/gotop/main.go @@ -0,0 +1,247 @@ +// gotop (C) 2015 Paul Buetow (gotop@dev.buetow.org) + +package main + +import ( + "container/list" + "errors" + "flag" + "fmt" + "github.com/buetow/gotop/diskstats" + "github.com/buetow/gotop/process" + "github.com/buetow/gotop/utils" + "golang.org/x/crypto/ssh/terminal" + "log" + "os" + "os/signal" + "syscall" + "time" +) + +var config struct { + banner string + interval time.Duration + binary *bool + mode *int + modeName string +} + +type twoP struct { + first, second process.Process + diff, diffR, diffW int + exited bool +} +type mapP map[string]twoP + +func timedGather(tChan <-chan bool, dRxChan chan<- diskstats.Diskstats, pRxChan chan<- process.Process) { + for { + switch <-tChan { + case false: + { + break + } + case true: + { + go diskstats.Gather(dRxChan) + go process.Gather(pRxChan) + } + } + } + close(dRxChan) + close(pRxChan) +} + +func receiveD(dRxChan <-chan diskstats.Diskstats) { + for d := range dRxChan { + //diskstats.Print() + // Implemented later + _ = d + } +} + +func sortP(lastP *mapP) *list.List { + remove := list.New() + sorted := list.New() + + for _, val := range *lastP { + nowTimestamp := int32(time.Now().Unix()) + if val.first.Timestamp+2 < nowTimestamp { + // Schedule remove obsolete pids from lastP + remove.PushBack(val.first.Id) + // Display this process one more time, but in a fancy way + val.exited = true + } + + if val.diff > 0 { + // Insertion sort + if sorted.Len() > 0 { + for e := sorted.Front(); e != nil; e = e.Next() { + diff := e.Value.(twoP).diff + if diff < val.diff { + //fmt.Printf("Inserting %d before %d\n", val.diff, diff) + sorted.InsertBefore(val, e) + break + } + } + } else { + sorted.PushFront(val) + } + } + } + + // Rremove obsolete pids from lastP + for e := remove.Front(); e != nil; e = e.Next() { + id := e.Value.(string) + //fmt.Println("Removing stale process: " + id) + delete(*lastP, id) + } + + return sorted +} + +func printP(sortedP *list.List) { + tWidth, tHeight, err := terminal.GetSize(0) + if err != nil { + log.Fatal(err) + } + + // Clear the screen + print header + fmt.Printf("\033[H\033[2J") + fmt.Printf("Mode: %s, Interval: %s\n", config.modeName, config.interval) + fmt.Printf("(Hit Ctr-C to quit, re-run with -h for flags)\n") + fmt.Printf("%5s/%5s %5s %s\n", "WRITE", "READS", "PID", "COMMAND") + + // Print the results + row := 3 + for e := sortedP.Front(); e != nil; e = e.Next() { + row++ + if row > tHeight { + break + } + val := e.Value.(twoP) + first := val.first + + var outstr string + + if val.exited { + outstr = fmt.Sprintf("XXXXXXXXXXX %5d %s", first.Pid, first.Cmdline) + + } else { + var humanW, humanR string + + if *config.binary { + humanW, humanR = utils.HumanBinary(val.diffW), utils.HumanBinary(val.diffR) + } else { + humanW, humanR = utils.Human(val.diffW), utils.Human(val.diffR) + } + + outstr = fmt.Sprintf("%5s %5s %5d %s", humanW, humanR, first.Pid, first.Cmdline) + } + + l := len(outstr) + if l > tWidth { + l = tWidth + } + fmt.Printf("%s\n", outstr[0:l]) + } +} + +func modeNames() (string, string, string, error) { + switch *config.mode { + case 0: + return "read_bytes", "write_bytes", "bytes", nil + case 1: + return "syscr", "syscw", "syscalls", nil + case 2: + return "rchar", "wchar", "chars", nil + } + + errstr := fmt.Sprintf("No such mode: %d\n", *config.mode) + return "", "", "", errors.New(errstr) +} + +func receiveP(pRxChan <-chan process.Process) { + lastP := make(mapP) + flag := false + + readKey, writeKey, modeName, err := modeNames() + if err != nil { + log.Fatal(err) + } + config.modeName = modeName + + makeDiff := func(first, second process.Process) twoP { + firstValR, firstValW := first.Count[readKey], first.Count[writeKey] + secondValR, secondValW := second.Count[readKey], second.Count[writeKey] + diffR, diffW := utils.Abs(firstValR-secondValR), utils.Abs(firstValW-secondValW) + diff := diffR + diffW + return twoP{first, second, diff, diffR, diffW, false} + } + + for p := range pRxChan { + if p.Last { + if flag { + printP(sortP(&lastP)) + } + flag = !flag + } else { + if val, ok := lastP[p.Id]; ok { + if flag { + lastP[p.Id] = makeDiff(val.first, p) + } else { + lastP[p.Id] = makeDiff(p, val.second) + } + } else { + lastP[p.Id] = twoP{first: p} + } + } + } +} + +func parseFlags() { + helpF := flag.Bool("v", false, "Print the version") + interF := flag.Int("i", 2, "Update interval in seconds") + + config.binary = flag.Bool("b", false, "Use binary instead of decimal (e.g. kiB an not kB)") + config.mode = flag.Int("m", 1, "The stats mode: 0:bytes 1:syscalls 2:chars") + + flag.Parse() + + config.banner = "gotop v0.1 (C) 2015 Paul buetow " + + if *helpF { + fmt.Println(config.banner) + os.Exit(0) + } + + config.interval = time.Duration(*interF) * time.Second +} + +func main() { + parseFlags() + + tChan := make(chan bool) + dRxChan := make(chan diskstats.Diskstats) + pRxChan := make(chan process.Process) + + go timedGather(tChan, dRxChan, pRxChan) + go receiveD(dRxChan) + go receiveP(pRxChan) + + termChan := make(chan os.Signal, 1) + signal.Notify(termChan, os.Interrupt) + signal.Notify(termChan, syscall.SIGTERM) + + go func() { + <-termChan + tChan <- false + fmt.Println("Good bye! This was:") + fmt.Println(config.banner) + os.Exit(0) + }() + + for { + tChan <- true + time.Sleep(config.interval) + } +} diff --git a/gstat/main.go b/gstat/main.go deleted file mode 100644 index 27aeee3..0000000 --- a/gstat/main.go +++ /dev/null @@ -1,247 +0,0 @@ -// gstat (C) 2015 Paul Buetow (gstat@dev.buetow.org) - -package main - -import ( - "container/list" - "errors" - "flag" - "fmt" - "github.com/buetow/gstat/diskstats" - "github.com/buetow/gstat/process" - "github.com/buetow/gstat/utils" - "golang.org/x/crypto/ssh/terminal" - "log" - "os" - "os/signal" - "syscall" - "time" -) - -var config struct { - banner string - interval time.Duration - binary *bool - mode *int - modeName string -} - -type twoP struct { - first, second process.Process - diff, diffR, diffW int - exited bool -} -type mapP map[string]twoP - -func timedGather(tChan <-chan bool, dRxChan chan<- diskstats.Diskstats, pRxChan chan<- process.Process) { - for { - switch <-tChan { - case false: - { - break - } - case true: - { - go diskstats.Gather(dRxChan) - go process.Gather(pRxChan) - } - } - } - close(dRxChan) - close(pRxChan) -} - -func receiveD(dRxChan <-chan diskstats.Diskstats) { - for d := range dRxChan { - //diskstats.Print() - // Implemented later - _ = d - } -} - -func sortP(lastP *mapP) *list.List { - remove := list.New() - sorted := list.New() - - for _, val := range *lastP { - nowTimestamp := int32(time.Now().Unix()) - if val.first.Timestamp+2 < nowTimestamp { - // Schedule remove obsolete pids from lastP - remove.PushBack(val.first.Id) - // Display this process one more time, but in a fancy way - val.exited = true - } - - if val.diff > 0 { - // Insertion sort - if sorted.Len() > 0 { - for e := sorted.Front(); e != nil; e = e.Next() { - diff := e.Value.(twoP).diff - if diff < val.diff { - //fmt.Printf("Inserting %d before %d\n", val.diff, diff) - sorted.InsertBefore(val, e) - break - } - } - } else { - sorted.PushFront(val) - } - } - } - - // Rremove obsolete pids from lastP - for e := remove.Front(); e != nil; e = e.Next() { - id := e.Value.(string) - //fmt.Println("Removing stale process: " + id) - delete(*lastP, id) - } - - return sorted -} - -func printP(sortedP *list.List) { - tWidth, tHeight, err := terminal.GetSize(0) - if err != nil { - log.Fatal(err) - } - - // Clear the screen + print header - fmt.Printf("\033[H\033[2J") - fmt.Printf("Mode: %s, Interval: %s\n", config.modeName, config.interval) - fmt.Printf("(Hit Ctr-C to quit, re-run with -h for flags)\n") - fmt.Printf("%5s/%5s %5s %s\n", "WRITE", "READS", "PID", "COMMAND") - - // Print the results - row := 3 - for e := sortedP.Front(); e != nil; e = e.Next() { - row++ - if row > tHeight { - break - } - val := e.Value.(twoP) - first := val.first - - var outstr string - - if val.exited { - outstr = fmt.Sprintf("XXXXXXXXXXX %5d %s", first.Pid, first.Cmdline) - - } else { - var humanW, humanR string - - if *config.binary { - humanW, humanR = utils.HumanBinary(val.diffW), utils.HumanBinary(val.diffR) - } else { - humanW, humanR = utils.Human(val.diffW), utils.Human(val.diffR) - } - - outstr = fmt.Sprintf("%5s %5s %5d %s", humanW, humanR, first.Pid, first.Cmdline) - } - - l := len(outstr) - if l > tWidth { - l = tWidth - } - fmt.Printf("%s\n", outstr[0:l]) - } -} - -func modeNames() (string, string, string, error) { - switch *config.mode { - case 0: - return "read_bytes", "write_bytes", "bytes", nil - case 1: - return "syscr", "syscw", "syscalls", nil - case 2: - return "rchar", "wchar", "chars", nil - } - - errstr := fmt.Sprintf("No such mode: %d\n", *config.mode) - return "", "", "", errors.New(errstr) -} - -func receiveP(pRxChan <-chan process.Process) { - lastP := make(mapP) - flag := false - - readKey, writeKey, modeName, err := modeNames() - if err != nil { - log.Fatal(err) - } - config.modeName = modeName - - makeDiff := func(first, second process.Process) twoP { - firstValR, firstValW := first.Count[readKey], first.Count[writeKey] - secondValR, secondValW := second.Count[readKey], second.Count[writeKey] - diffR, diffW := utils.Abs(firstValR-secondValR), utils.Abs(firstValW-secondValW) - diff := diffR + diffW - return twoP{first, second, diff, diffR, diffW, false} - } - - for p := range pRxChan { - if p.Last { - if flag { - printP(sortP(&lastP)) - } - flag = !flag - } else { - if val, ok := lastP[p.Id]; ok { - if flag { - lastP[p.Id] = makeDiff(val.first, p) - } else { - lastP[p.Id] = makeDiff(p, val.second) - } - } else { - lastP[p.Id] = twoP{first: p} - } - } - } -} - -func parseFlags() { - helpF := flag.Bool("v", false, "Print the version") - interF := flag.Int("i", 2, "Update interval in seconds") - - config.binary = flag.Bool("b", false, "Use binary instead of decimal (e.g. kiB an not kB)") - config.mode = flag.Int("m", 1, "The stats mode: 0:bytes 1:syscalls 2:chars") - - flag.Parse() - - config.banner = "gstat v0.1 (C) 2015 Paul buetow " - - if *helpF { - fmt.Println(config.banner) - os.Exit(0) - } - - config.interval = time.Duration(*interF) * time.Second -} - -func main() { - parseFlags() - - tChan := make(chan bool) - dRxChan := make(chan diskstats.Diskstats) - pRxChan := make(chan process.Process) - - go timedGather(tChan, dRxChan, pRxChan) - go receiveD(dRxChan) - go receiveP(pRxChan) - - termChan := make(chan os.Signal, 1) - signal.Notify(termChan, os.Interrupt) - signal.Notify(termChan, syscall.SIGTERM) - - go func() { - <-termChan - tChan <- false - fmt.Println("Good bye! This was:") - fmt.Println(config.banner) - os.Exit(0) - }() - - for { - tChan <- true - time.Sleep(config.interval) - } -} diff --git a/process/process.go b/process/process.go index 53db8b7..a30693d 100644 --- a/process/process.go +++ b/process/process.go @@ -2,7 +2,7 @@ package process import ( "fmt" - "github.com/buetow/gstat/utils" + "github.com/buetow/gotop/utils" "io/ioutil" "log" "regexp" -- cgit v1.2.3