performance optimization for render rate

This commit is contained in:
sqshq 2019-02-23 23:42:52 -05:00
parent 6e27c2e5a8
commit ecd6344269
7 changed files with 114 additions and 58 deletions

View File

@ -8,15 +8,16 @@ import (
)
const (
RenderRate = 100 * time.Millisecond
Title = "sampler"
MaxRenderInterval = 1000 * time.Millisecond
MinRenderInterval = 100 * time.Millisecond
AppTitle = "sampler"
)
type Console struct{}
func (self *Console) Init() {
fmt.Printf("\033]0;%s\007", Title)
fmt.Printf("\033]0;%s\007", AppTitle)
if err := ui.Init(); err != nil {
log.Fatalf("failed to initialize termui: %v", err)

View File

@ -33,9 +33,9 @@ type Palette struct {
func GetPalette(theme Theme) Palette {
switch theme {
case ThemeDark:
return Palette{Colors: []ui.Color{ColorOlive, ColorDeepSkyBlue, ColorDeepPink, ColorWhite, ColorPurple, ColorCian, ColorOrange, ColorGreen}}
return Palette{Colors: []ui.Color{ColorOlive, ColorDeepSkyBlue, ColorDeepPink, ColorWhite, ColorGreen, ColorOrange, ColorCian, ColorPurple}}
case ThemeLight:
return Palette{Colors: []ui.Color{ColorOlive, ColorDeepSkyBlue, ColorDeepPink, ColorWhite, ColorPurple, ColorCian, ColorOrange, ColorGreen}}
return Palette{Colors: []ui.Color{ColorOlive, ColorDeepSkyBlue, ColorDeepPink, ColorWhite, ColorGreen, ColorOrange, ColorCian, ColorPurple}}
default:
panic(fmt.Sprintf("Following theme is not supported: %v", theme))
}

View File

@ -24,8 +24,8 @@ func NewSampler(consumer Consumer, item Item, rateMs int) Sampler {
return sampler
}
func (self *Sampler) sample() {
value, err := self.item.nextValue()
sample := Sample{Value: value, Error: err, Label: *self.item.Label}
self.consumer.ConsumeSample(sample)
func (s *Sampler) sample() {
value, err := s.item.nextValue()
sample := Sample{Value: value, Error: err, Label: *s.item.Label}
s.consumer.ConsumeSample(sample)
}

View File

@ -8,44 +8,97 @@ import (
"time"
)
const (
refreshRateToRenderRateRatio = 0.8
)
type Handler struct {
Layout *widgets.Layout
RenderEvents <-chan time.Time
ConsoleEvents <-chan ui.Event
layout *widgets.Layout
renderTicker *time.Ticker
consoleEvents <-chan ui.Event
renderRate time.Duration
}
func NewHandler(layout *widgets.Layout) Handler {
renderRate := calcMinRenderRate(layout)
return Handler{
layout: layout,
consoleEvents: ui.PollEvents(),
renderTicker: time.NewTicker(renderRate),
renderRate: renderRate,
}
}
func (h *Handler) HandleEvents() {
// initial render
ui.Render(h.layout)
pause := false
for {
select {
case <-h.RenderEvents:
if !pause {
ui.Render(h.Layout)
}
case e := <-h.ConsoleEvents:
case mode := <-h.layout.ChangeModeEvents:
h.handleModeChange(mode)
case <-h.renderTicker.C:
ui.Render(h.layout)
case e := <-h.consoleEvents:
switch e.ID {
case console.KeyQuit, console.KeyExit:
h.handleExit()
return
case console.KeyPause:
pause = !pause
pause = !pause // TODO move to layout, since it will show PAUSE sign in status line, pause/unpause can be sent via channel
case console.SignalResize:
payload := e.Payload.(ui.Resize)
h.Layout.ChangeDimensions(payload.Width, payload.Height)
h.layout.ChangeDimensions(payload.Width, payload.Height)
default:
h.Layout.HandleConsoleEvent(e.ID)
h.layout.HandleConsoleEvent(e.ID)
}
}
}
}
func (h *Handler) handleModeChange(m widgets.Mode) {
// render mode change before switching the tickers
ui.Render(h.layout)
h.renderTicker.Stop()
if m == widgets.ModeDefault {
h.renderTicker = time.NewTicker(h.renderRate)
} else {
h.renderTicker = time.NewTicker(console.MinRenderInterval)
}
}
func (h *Handler) handleExit() {
var settings []config.ComponentSettings
for _, c := range h.Layout.Components {
for _, c := range h.layout.Components {
settings = append(settings,
config.ComponentSettings{Type: c.Type, Title: c.Title, Size: c.Size, Position: c.Position})
}
config.Update(settings)
}
func calcMinRenderRate(layout *widgets.Layout) time.Duration {
minRefreshRateMs := layout.Components[0].RefreshRateMs
for _, c := range layout.Components {
if c.RefreshRateMs < minRefreshRateMs {
minRefreshRateMs = c.RefreshRateMs
}
}
renderRate := time.Duration(
int(float64(minRefreshRateMs)*refreshRateToRenderRateRatio)) * time.Millisecond
if renderRate < console.MinRenderInterval {
return console.MinRenderInterval
}
if renderRate > console.MaxRenderInterval {
return console.MaxRenderInterval
}
return renderRate
}

14
main.go
View File

@ -10,7 +10,6 @@ import (
"github.com/sqshq/sampler/widgets/barchart"
"github.com/sqshq/sampler/widgets/runchart"
ui "github.com/sqshq/termui"
"time"
)
func main() {
@ -27,7 +26,7 @@ func main() {
legend := runchart.Legend{Enabled: c.Legend.Enabled, Details: c.Legend.Details}
chart := runchart.NewRunChart(c.Title, *c.Scale, *c.RefreshRateMs, legend)
layout.AddComponent(chart, c.Title, c.Position, c.Size, config.TypeRunChart)
layout.AddComponent(config.TypeRunChart, chart, c.Title, c.Position, c.Size, *c.RefreshRateMs)
for _, item := range c.Items {
chart.AddLine(*item.Label, *item.Color)
@ -37,14 +36,14 @@ func main() {
for _, a := range cfg.AsciiBoxes {
box := asciibox.NewAsciiBox(a.Title, *a.Font, *a.Item.Color)
layout.AddComponent(box, a.Title, a.Position, a.Size, config.TypeAsciiBox)
layout.AddComponent(config.TypeAsciiBox, box, a.Title, a.Position, a.Size, *a.RefreshRateMs)
data.NewSampler(box, a.Item, *a.RefreshRateMs)
}
for _, c := range cfg.BarCharts {
chart := barchart.NewBarChart(c.Title, *c.Scale)
layout.AddComponent(chart, c.Title, c.Position, c.Size, config.TypeBarChart)
layout.AddComponent(config.TypeBarChart, chart, c.Title, c.Position, c.Size, *c.RefreshRateMs)
for _, item := range c.Items {
chart.AddBar(*item.Label, *item.Color)
@ -52,11 +51,6 @@ func main() {
}
}
handler := event.Handler{
Layout: layout,
RenderEvents: time.NewTicker(console.RenderRate).C,
ConsoleEvents: ui.PollEvents(),
}
handler := event.NewHandler(layout)
handler.HandleEvents()
}

View File

@ -6,11 +6,12 @@ import (
)
type Component struct {
Drawable ui.Drawable
Title string
Position config.Position
Size config.Size
Type config.ComponentType
Type config.ComponentType
Drawable ui.Drawable
Title string
Position config.Position
Size config.Size
RefreshRateMs int
}
func (c *Component) Move(x, y int) {

View File

@ -9,10 +9,11 @@ import (
type Layout struct {
ui.Block
Components []Component
menu *Menu
mode Mode
selection int
Components []Component
ChangeModeEvents chan Mode
mode Mode
menu *Menu
selection int
}
type Mode rune
@ -37,16 +38,17 @@ func NewLayout(width, height int, menu *Menu) *Layout {
block.SetRect(0, 0, width, height)
return &Layout{
Block: block,
Components: make([]Component, 0),
menu: menu,
mode: ModeDefault,
selection: 0,
Block: block,
Components: make([]Component, 0),
menu: menu,
mode: ModeDefault,
selection: 0,
ChangeModeEvents: make(chan Mode, 10),
}
}
func (l *Layout) AddComponent(drawable ui.Drawable, title string, position config.Position, size config.Size, Type config.ComponentType) {
l.Components = append(l.Components, Component{drawable, title, position, size, Type})
func (l *Layout) AddComponent(Type config.ComponentType, drawable ui.Drawable, title string, position config.Position, size config.Size, refreshRateMs int) {
l.Components = append(l.Components, Component{Type, drawable, title, position, size, refreshRateMs})
}
func (l *Layout) GetComponents(Type config.ComponentType) []ui.Drawable {
@ -62,36 +64,41 @@ func (l *Layout) GetComponents(Type config.ComponentType) []ui.Drawable {
return components
}
func (l *Layout) changeMode(m Mode) {
l.mode = m
l.ChangeModeEvents <- m
}
func (l *Layout) HandleConsoleEvent(e string) {
switch e {
case console.KeyEnter:
switch l.mode {
case ModeComponentSelect:
l.menu.choose()
l.mode = ModeMenuOptionSelect
l.changeMode(ModeMenuOptionSelect)
case ModeMenuOptionSelect:
option := l.menu.getSelectedOption()
switch option {
case MenuOptionMove:
l.mode = ModeComponentMove
l.changeMode(ModeComponentMove)
l.menu.moveOrResize()
case MenuOptionResize:
l.mode = ModeComponentResize
l.changeMode(ModeComponentResize)
l.menu.moveOrResize()
case MenuOptionPinpoint:
l.mode = ModeChartPinpoint
l.changeMode(ModeChartPinpoint)
l.menu.idle()
chart := l.getSelectedComponent().Drawable.(*runchart.RunChart)
chart.MoveSelection(0)
case MenuOptionResume:
l.mode = ModeDefault
l.changeMode(ModeDefault)
l.menu.idle()
}
case ModeComponentMove:
fallthrough
case ModeComponentResize:
l.menu.idle()
l.mode = ModeDefault
l.changeMode(ModeDefault)
}
case console.KeyEsc:
switch l.mode {
@ -103,12 +110,12 @@ func (l *Layout) HandleConsoleEvent(e string) {
fallthrough
case ModeMenuOptionSelect:
l.menu.idle()
l.mode = ModeDefault
l.changeMode(ModeDefault)
}
case console.KeyLeft:
switch l.mode {
case ModeDefault:
l.mode = ModeComponentSelect
l.changeMode(ModeComponentSelect)
l.selection = 0
l.menu.highlight(l.getComponent(l.selection))
case ModeChartPinpoint:
@ -127,7 +134,7 @@ func (l *Layout) HandleConsoleEvent(e string) {
case console.KeyRight:
switch l.mode {
case ModeDefault:
l.mode = ModeComponentSelect
l.changeMode(ModeComponentSelect)
l.selection = 0
l.menu.highlight(l.getComponent(l.selection))
case ModeChartPinpoint:
@ -146,7 +153,7 @@ func (l *Layout) HandleConsoleEvent(e string) {
case console.KeyUp:
switch l.mode {
case ModeDefault:
l.mode = ModeComponentSelect
l.changeMode(ModeComponentSelect)
l.selection = 0
l.menu.highlight(l.getComponent(l.selection))
case ModeComponentSelect:
@ -164,7 +171,7 @@ func (l *Layout) HandleConsoleEvent(e string) {
case console.KeyDown:
switch l.mode {
case ModeDefault:
l.mode = ModeComponentSelect
l.changeMode(ModeComponentSelect)
l.selection = 0
l.menu.highlight(l.getComponent(l.selection))
case ModeComponentSelect: