performance optimization for render rate
This commit is contained in:
parent
6e27c2e5a8
commit
ecd6344269
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
14
main.go
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue