From 61e13eb5e62b457660c0f03f8e00746fc4299ac2 Mon Sep 17 00:00:00 2001 From: Armin Date: Sun, 14 Mar 2021 21:30:53 +0100 Subject: [PATCH] Fix terminate bug --- internal/collection/collection.go | 13 ++++++++++ internal/model/model.go | 2 +- internal/model/model_test.go | 38 +++++++++++++--------------- internal/ui/ui.go | 42 +++++++++++++------------------ 4 files changed, 49 insertions(+), 46 deletions(-) create mode 100644 internal/collection/collection.go diff --git a/internal/collection/collection.go b/internal/collection/collection.go new file mode 100644 index 0000000..35cabe4 --- /dev/null +++ b/internal/collection/collection.go @@ -0,0 +1,13 @@ +package collection + +import "strings" + +// SliceContains contains true if the input slice contains the provided substring +func SliceContains(ss []string, subString string) bool { + for _, s := range ss { + if strings.Contains(s, subString) { + return true + } + } + return false +} diff --git a/internal/model/model.go b/internal/model/model.go index 235cb71..1f34363 100644 --- a/internal/model/model.go +++ b/internal/model/model.go @@ -155,7 +155,7 @@ func ParseStackFrame(reader io.Reader) (routines []Goroutine, err error) { continue } - routine.StackTrace = make([]StackFrame, 0) + routine.StackTrace = make([]StackFrame, 0, 8) for scanner.Scan() { traceLine := scanner.Text() diff --git a/internal/model/model_test.go b/internal/model/model_test.go index 4b31b02..55f8b57 100644 --- a/internal/model/model_test.go +++ b/internal/model/model_test.go @@ -114,12 +114,6 @@ func TestParseTrace(t *testing.T) { assert.False(t, r3.LockedToThread) } -func Benchmark_ParseTrace(b *testing.B) { - for n := 0; n < b.N; n++ { - model.ParseStackFrame(strings.NewReader(trace_1)) - } -} - var trace_2 = `goroutine 268 [runnable, locked to thread]: syscall.Syscall9(0x7ff9af9b0500, 0x7, 0x1f4, 0xc0000902d8, 0x1, 0xc0000902c8, 0xc000090348, 0xc000090298, 0x0, 0x0, ...) C:/Program Files/Go/src/runtime/syscall_windows.go:356 +0xf2 @@ -140,12 +134,6 @@ func TestParseLockedToThread(t *testing.T) { assert.True(t, r0.LockedToThread) } -func Benchmark_ParseStackPos(b *testing.B) { - for n := 0; n < b.N; n++ { - model.ParseStackPos("C:/Program Files/Go/src/runtime/syscall_windows.go:356 +0xf2") - } -} - func Test_ParseStackPos_Invalid(t *testing.T) { _, _, _, err := model.ParseStackPos("C:/Program Files/Go/src/runtime/syscall_windows.go:356 f+0xf2") assert.NotNil(t, err) @@ -161,14 +149,6 @@ func Test_ParseStackPos_Valid(t *testing.T) { assert.Equal(t, 0xf2, *pos) } -///usr/local/go/src/net/http/server.go:2969 +0x970 - -func Benchmark_ParseHeader(b *testing.B) { - for n := 0; n < b.N; n++ { - model.ParseHeader("goroutine 268 [runnable, locked to thread]:") - } -} - func Test_ParseHeader_Invalid(t *testing.T) { _, err := model.ParseHeader("") assert.NotNil(t, err) @@ -199,3 +179,21 @@ func Test_ParseHeader_Valid(t *testing.T) { assert.Equal(t, int64(16), result.WaitSinceMin) assert.Equal(t, true, result.LockedToThread) } + +func Benchmark_ParseTrace(b *testing.B) { + for n := 0; n < b.N; n++ { + model.ParseStackFrame(strings.NewReader(trace_1)) + } +} + +func Benchmark_ParseStackPos(b *testing.B) { + for n := 0; n < b.N; n++ { + model.ParseStackPos("C:/Program Files/Go/src/runtime/syscall_windows.go:356 +0xf2") + } +} + +func Benchmark_ParseHeader(b *testing.B) { + for n := 0; n < b.N; n++ { + model.ParseHeader("goroutine 268 [runnable, locked to thread]:") + } +} diff --git a/internal/ui/ui.go b/internal/ui/ui.go index ff9a2f5..e8f5f1f 100644 --- a/internal/ui/ui.go +++ b/internal/ui/ui.go @@ -6,6 +6,7 @@ import ( "sort" "strings" + "github.com/becheran/roumon/internal/collection" "github.com/becheran/roumon/internal/model" "github.com/gizak/termui/v3/widgets" @@ -13,11 +14,10 @@ import ( ) const ( - padding = 1 + padding = 1 + keepRoutineHist = 100 ) -var keepRoutineHist = 100 - type UI struct { list *widgets.List filter *widgets.Paragraph @@ -155,15 +155,6 @@ func NewUI() *UI { return &ui } -func sliceContains(ss []string, subString string) bool { - for _, s := range ss { - if strings.Contains(s, subString) { - return true - } - } - return false -} - func (ui *UI) updateStatus() { typeCount := make(map[string]float64) for i := 0; i < len(ui.origData); i++ { @@ -183,7 +174,7 @@ func (ui *UI) updateStatus() { for idx, t := range types { data[idx] = typeCount[t] newLabel := t[:3] - if sliceContains(labels, newLabel) { + if collection.SliceContains(labels, newLabel) { newLabel = fmt.Sprintf("%s%d", t[:2], uniqueID) uniqueID++ } @@ -213,12 +204,11 @@ func (ui *UI) updateList() { } } - // TODO: prevent always doing this! - routineList := make([]string, len(ui.filteredData)) + // Update list + ui.list.Rows = make([]string, len(ui.filteredData)) for i := 0; i < len(ui.filteredData); i++ { - routineList[i] = fmt.Sprintf("%05d %s ", ui.filteredData[i].ID, ui.filteredData[i].Status) + ui.list.Rows[i] = fmt.Sprintf("%05d %s ", ui.filteredData[i].ID, ui.filteredData[i].Status) } - ui.list.Rows = routineList if len(ui.filteredData) == 0 { ui.list.SelectedRow = 0 @@ -294,7 +284,11 @@ func (ui *UI) Run(terminate chan<- error, routinesUpdate <-chan []model.Goroutin ui.resize(resized.Width, resized.Height) } case termui.KeyboardEvent: - ui.handleKeyEvent(evt.ID, terminate, pollEvents) + terminateEvent := ui.handleKeyEvent(evt.ID, pollEvents) + if terminateEvent { + terminate <- nil + return + } } case routines := <-routinesUpdate: // History data size cannot be limited in termui. This is a workaround @@ -313,17 +307,15 @@ func (ui *UI) Run(terminate chan<- error, routinesUpdate <-chan []model.Goroutin } } -func (ui *UI) handleKeyEvent(keyID string, terminate chan<- error, pollEvents <-chan termui.Event) { +func (ui *UI) handleKeyEvent(keyID string, pollEvents <-chan termui.Event) (terminate bool) { switch keyID { case "", "": - terminate <- nil - return + return true case "": termui.Render(ui.grid, ui.legend, ui.help) e := <-pollEvents if e.ID == "" || e.ID == "" { - terminate <- nil - return + return true } termui.Render(ui.grid, ui.legend) case "": @@ -331,8 +323,7 @@ func (ui *UI) handleKeyEvent(keyID string, terminate chan<- error, pollEvents <- termui.Render(ui.grid, ui.legend, ui.paused) e := <-pollEvents if e.ID == "" || e.ID == "" { - terminate <- nil - return + return true } termui.Render(ui.grid, ui.legend) case "": @@ -375,4 +366,5 @@ func (ui *UI) handleKeyEvent(keyID string, terminate chan<- error, pollEvents <- } ui.updateList() } + return false }