Skip to content

Commit

Permalink
Merge pull request davecheney#19 from kouno/go15-support
Browse files Browse the repository at this point in the history
Go 1.5 support + Refactor
  • Loading branch information
kouno committed Oct 16, 2015
2 parents 3fbe87c + 500a10e commit 2497dda
Show file tree
Hide file tree
Showing 9 changed files with 355 additions and 106 deletions.
4 changes: 2 additions & 2 deletions graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ func (g *Graph) setTmpl(tmplStr string) {
g.Tmpl = template.Must(template.New("vis").Parse(tmplStr))
}

func (g *Graph) write(w io.Writer) {
func (g *Graph) Write(w io.Writer) error {
g.mu.RLock()
defer g.mu.RUnlock()
g.Tmpl.Execute(w, g)
return g.Tmpl.Execute(w, g)
}

func (g *Graph) AddGCTraceGraphPoint(gcTrace *gctrace) {
Expand Down
61 changes: 61 additions & 0 deletions http_server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package main

import (
"fmt"
"log"
"net"
"net/http"
"sync"
)

type HttpServer struct {
graph *Graph
listener net.Listener
iface string
port string

listenerMtx sync.Mutex
}

func NewHttpServer(iface string, port string, graph *Graph) *HttpServer {
h := &HttpServer{
graph: graph,
iface: iface,
port: port,
}

return h
}

func (h *HttpServer) Start() {
http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
h.graph.Write(w)
})
http.Serve(h.Listener(), nil)
}

func (h *HttpServer) Close() {
h.Listener().Close()
}

func (h *HttpServer) Url() string {
return fmt.Sprintf("http://%s/", h.Listener().Addr())
}

func (h *HttpServer) Listener() net.Listener {
h.listenerMtx.Lock()
defer h.listenerMtx.Unlock()

if h.listener != nil {
return h.listener
}

ifaceAndPort := fmt.Sprintf("%v:%v", h.iface, h.port)
listener, err := net.Listen("tcp4", ifaceAndPort)
if err != nil {
log.Fatal(err)
}

h.listener = listener
return h.listener
}
59 changes: 59 additions & 0 deletions http_server_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package main

import (
"bytes"
"io/ioutil"
"net/http"
"strings"
"testing"
)

func TestHttpServerListener(t *testing.T) {
graph := NewGraph("fake title", GCVIS_TMPL)
server := NewHttpServer("127.0.0.1", "0", &graph)

url := server.Url()

if !strings.Contains(url, "http://127.0.0.1") {
t.Fatalf("Server URL didn't contain localhost address: %v", url)
}
}

func TestHttpServerResponse(t *testing.T) {
graph := NewGraph("fake title", GCVIS_TMPL)
graph.AddGCTraceGraphPoint(&gctrace{})
server := NewHttpServer("127.0.0.1", "0", &graph)

go server.Start()
defer server.Close()

response, err := http.Get(server.Url())
if err != nil {
t.Errorf("HTTP request returned an error: %v", err)
}
defer response.Body.Close()

body, err := ioutil.ReadAll(response.Body)
if err != nil {
t.Errorf("Error while reading response body: %v", err)
}

w := &bytes.Buffer{}

if err = graph.Write(w); err != nil {
t.Errorf("Error while writing template: %v", err)
}

expectedBody, err := ioutil.ReadAll(w)
if err != nil {
t.Errorf("Error while reading buffer: %v", err)
}

if !bytes.Equal(expectedBody, body) {
t.Fatalf(
"Expected response body to equal parsed template.\nExpected: %v\nGot: %v",
string(expectedBody),
string(body),
)
}
}
64 changes: 26 additions & 38 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// gzvis is a tool to assist you visualising the operation of
// gcvis is a tool to assist you visualising the operation of
// the go runtime garbage collector.
//
// usage:
Expand All @@ -10,26 +10,16 @@ import (
"flag"
"fmt"
"log"
"net"
"net/http"
"os"
"strings"

"github.com/pkg/browser"
)

var gcvisGraph Graph

func indexHandler(w http.ResponseWriter, req *http.Request) {
gcvisGraph.write(w)
}

var iface = flag.String("i", "127.0.0.1", "specify interface to use. defaults to 127.0.0.1.")
var iface = flag.String("i", "127.0.0.1", "specify interface to use. defaults to 127.0.0.1.")
var port = flag.String("p", "0", "specify port to use.")

func main() {

var err error

flag.Usage = func() {
fmt.Fprintf(os.Stderr, "Usage of %s: command <args>...\n", os.Args[0])
flag.PrintDefaults()
Expand All @@ -41,41 +31,39 @@ func main() {
return
}

ifaceAndPort := fmt.Sprintf("%v:0", *iface)
listener, err := net.Listen("tcp4", ifaceAndPort)
if err != nil {
log.Fatal(err)
}

pr, pw, _ := os.Pipe()
gcChan := make(chan *gctrace, 1)
scvgChan := make(chan *scvgtrace, 1)

parser := Parser{
reader: pr,
gcChan: gcChan,
scvgChan: scvgChan,
}

gcvisGraph = NewGraph(strings.Join(flag.Args(), " "), GCVIS_TMPL)
subcommand := NewSubCommand(flag.Args())
parser := NewParser(subcommand.PipeRead)
gcvisGraph := NewGraph(strings.Join(flag.Args(), " "), GCVIS_TMPL)
server := NewHttpServer(*iface, *port, &gcvisGraph)

go startSubprocess(pw, flag.Args())
go subcommand.Run()
go parser.Run()
go server.Start()

http.HandleFunc("/", indexHandler)

go http.Serve(listener, nil)

url := fmt.Sprintf("http://%s/", listener.Addr())
url := server.Url()
log.Printf("opening browser window, if this fails, navigate to %s", url)
browser.OpenURL(url)

for {
select {
case gcTrace := <-gcChan:
case gcTrace := <-parser.GcChan:
gcvisGraph.AddGCTraceGraphPoint(gcTrace)
case scvgTrace := <-scvgChan:
case scvgTrace := <-parser.ScvgChan:
gcvisGraph.AddScavengerGraphPoint(scvgTrace)
case output := <-parser.NoMatchChan:
fmt.Fprintln(os.Stderr, output)
case <-parser.done:
if parser.Err != nil {
fmt.Fprintf(os.Stderr, parser.Err.Error())
os.Exit(1)
}

if subcommand.Err() != nil {
fmt.Fprintf(os.Stderr, subcommand.Err().Error())
os.Exit(1)
}

os.Exit(0)
}
}
}
55 changes: 38 additions & 17 deletions parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,43 @@ package main

import (
"bufio"
"fmt"
"io"
"log"
"regexp"
"strconv"
)

const (
GCRegexp = `gc\d+\(\d+\): \d+\+\d+\+\d+\+\d+ us, \d+ -> (?P<Heap1>\d+) MB, \d+ \(\d+-\d+\) objects,( \d+ goroutines,)? \d+\/\d+\/\d+ sweeps, \d+\(\d+\) handoff, \d+\(\d+\) steal, \d+\/\d+\/\d+ yields`
SCVGRegexp = `scvg\d+: inuse: (?P<inuse>\d+), idle: (?P<idle>\d+), sys: (?P<sys>\d+), released: (?P<released>\d+), consumed: (?P<consumed>\d+) \(MB\)`
GCRegexpGo14 = `gc\d+\(\d+\): ([\d.]+\+?)+ us, \d+ -> (?P<Heap1>\d+) MB, \d+ \(\d+-\d+\) objects,( \d+ goroutines,)? \d+\/\d+\/\d+ sweeps, \d+\(\d+\) handoff, \d+\(\d+\) steal, \d+\/\d+\/\d+ yields`
GCRegexpGo15 = `gc \d+ @[\d.]+s \d+%: [\d.+/]+ ms clock, [\d.+/]+ ms cpu, \d+->\d+->\d+ MB, (?P<Heap1>\d+) MB goal, \d+ P`
SCVGRegexp = `scvg\d+: inuse: (?P<inuse>\d+), idle: (?P<idle>\d+), sys: (?P<sys>\d+), released: (?P<released>\d+), consumed: (?P<consumed>\d+) \(MB\)`
)

var (
gcre = regexp.MustCompile(GCRegexp)
scvgre = regexp.MustCompile(SCVGRegexp)
gcrego14 = regexp.MustCompile(GCRegexpGo14)
gcrego15 = regexp.MustCompile(GCRegexpGo15)
scvgre = regexp.MustCompile(SCVGRegexp)
)

type Parser struct {
reader io.Reader
gcChan chan *gctrace
scvgChan chan *scvgtrace
reader io.Reader
GcChan chan *gctrace
ScvgChan chan *scvgtrace
NoMatchChan chan string
done chan bool

Err error

scvgRegexp *regexp.Regexp
}

func NewParser(r io.Reader) *Parser {
return &Parser{
reader: r,
GcChan: make(chan *gctrace, 1),
ScvgChan: make(chan *scvgtrace, 1),
NoMatchChan: make(chan string, 1),
done: make(chan bool),
}
}

func (p *Parser) Run() {
Expand All @@ -31,25 +47,30 @@ func (p *Parser) Run() {
for sc.Scan() {
line := sc.Text()

if result := gcre.FindStringSubmatch(line); result != nil {
p.gcChan <- parseGCTrace(result)
if result := gcrego15.FindStringSubmatch(line); result != nil {
p.GcChan <- parseGCTrace(gcrego15, result)
continue
}

if result := gcrego14.FindStringSubmatch(line); result != nil {
p.GcChan <- parseGCTrace(gcrego14, result)
continue
}

if result := scvgre.FindStringSubmatch(line); result != nil {
p.scvgChan <- parseSCVGTrace(result)
p.ScvgChan <- parseSCVGTrace(result)
continue
}

fmt.Println(line)
p.NoMatchChan <- line
}

if err := sc.Err(); err != nil {
log.Fatal(err)
}
p.Err = sc.Err()

close(p.done)
}

func parseGCTrace(matches []string) *gctrace {
func parseGCTrace(gcre *regexp.Regexp, matches []string) *gctrace {
matchMap := getMatchMap(gcre, matches)

return &gctrace{
Expand Down
Loading

0 comments on commit 2497dda

Please sign in to comment.