performance optimization for render rate
This commit is contained in:
parent
6e27c2e5a8
commit
ecd6344269
|
@ -8,15 +8,16 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
RenderRate = 100 * time.Millisecond
|
MaxRenderInterval = 1000 * time.Millisecond
|
||||||
Title = "sampler"
|
MinRenderInterval = 100 * time.Millisecond
|
||||||
|
AppTitle = "sampler"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Console struct{}
|
type Console struct{}
|
||||||
|
|
||||||
func (self *Console) Init() {
|
func (self *Console) Init() {
|
||||||
|
|
||||||
fmt.Printf("\033]0;%s\007", Title)
|
fmt.Printf("\033]0;%s\007", AppTitle)
|
||||||
|
|
||||||
if err := ui.Init(); err != nil {
|
if err := ui.Init(); err != nil {
|
||||||
log.Fatalf("failed to initialize termui: %v", err)
|
log.Fatalf("failed to initialize termui: %v", err)
|
||||||
|
|
|
@ -33,9 +33,9 @@ type Palette struct {
|
||||||
func GetPalette(theme Theme) Palette {
|
func GetPalette(theme Theme) Palette {
|
||||||
switch theme {
|
switch theme {
|
||||||
case ThemeDark:
|
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:
|
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:
|
default:
|
||||||
panic(fmt.Sprintf("Following theme is not supported: %v", theme))
|
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
|
return sampler
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Sampler) sample() {
|
func (s *Sampler) sample() {
|
||||||
value, err := self.item.nextValue()
|
value, err := s.item.nextValue()
|
||||||
sample := Sample{Value: value, Error: err, Label: *self.item.Label}
|
sample := Sample{Value: value, Error: err, Label: *s.item.Label}
|
||||||
self.consumer.ConsumeSample(sample)
|
s.consumer.ConsumeSample(sample)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,44 +8,97 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
refreshRateToRenderRateRatio = 0.8
|
||||||
|
)
|
||||||
|
|
||||||
type Handler struct {
|
type Handler struct {
|
||||||
Layout *widgets.Layout
|
layout *widgets.Layout
|
||||||
RenderEvents <-chan time.Time
|
renderTicker *time.Ticker
|
||||||
ConsoleEvents <-chan ui.Event
|
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() {
|
func (h *Handler) HandleEvents() {
|
||||||
|
|
||||||
|
// initial render
|
||||||
|
ui.Render(h.layout)
|
||||||
pause := false
|
pause := false
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-h.RenderEvents:
|
case mode := <-h.layout.ChangeModeEvents:
|
||||||
if !pause {
|
h.handleModeChange(mode)
|
||||||
ui.Render(h.Layout)
|
case <-h.renderTicker.C:
|
||||||
}
|
ui.Render(h.layout)
|
||||||
case e := <-h.ConsoleEvents:
|
case e := <-h.consoleEvents:
|
||||||
switch e.ID {
|
switch e.ID {
|
||||||
case console.KeyQuit, console.KeyExit:
|
case console.KeyQuit, console.KeyExit:
|
||||||
h.handleExit()
|
h.handleExit()
|
||||||
return
|
return
|
||||||
case console.KeyPause:
|
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:
|
case console.SignalResize:
|
||||||
payload := e.Payload.(ui.Resize)
|
payload := e.Payload.(ui.Resize)
|
||||||
h.Layout.ChangeDimensions(payload.Width, payload.Height)
|
h.layout.ChangeDimensions(payload.Width, payload.Height)
|
||||||
default:
|
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() {
|
func (h *Handler) handleExit() {
|
||||||
var settings []config.ComponentSettings
|
var settings []config.ComponentSettings
|
||||||
for _, c := range h.Layout.Components {
|
for _, c := range h.layout.Components {
|
||||||
settings = append(settings,
|
settings = append(settings,
|
||||||
config.ComponentSettings{Type: c.Type, Title: c.Title, Size: c.Size, Position: c.Position})
|
config.ComponentSettings{Type: c.Type, Title: c.Title, Size: c.Size, Position: c.Position})
|
||||||
}
|
}
|
||||||
config.Update(settings)
|
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/barchart"
|
||||||
"github.com/sqshq/sampler/widgets/runchart"
|
"github.com/sqshq/sampler/widgets/runchart"
|
||||||
ui "github.com/sqshq/termui"
|
ui "github.com/sqshq/termui"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -27,7 +26,7 @@ func main() {
|
||||||
|
|
||||||
legend := runchart.Legend{Enabled: c.Legend.Enabled, Details: c.Legend.Details}
|
legend := runchart.Legend{Enabled: c.Legend.Enabled, Details: c.Legend.Details}
|
||||||
chart := runchart.NewRunChart(c.Title, *c.Scale, *c.RefreshRateMs, legend)
|
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 {
|
for _, item := range c.Items {
|
||||||
chart.AddLine(*item.Label, *item.Color)
|
chart.AddLine(*item.Label, *item.Color)
|
||||||
|
@ -37,14 +36,14 @@ func main() {
|
||||||
|
|
||||||
for _, a := range cfg.AsciiBoxes {
|
for _, a := range cfg.AsciiBoxes {
|
||||||
box := asciibox.NewAsciiBox(a.Title, *a.Font, *a.Item.Color)
|
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)
|
data.NewSampler(box, a.Item, *a.RefreshRateMs)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cfg.BarCharts {
|
for _, c := range cfg.BarCharts {
|
||||||
|
|
||||||
chart := barchart.NewBarChart(c.Title, *c.Scale)
|
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 {
|
for _, item := range c.Items {
|
||||||
chart.AddBar(*item.Label, *item.Color)
|
chart.AddBar(*item.Label, *item.Color)
|
||||||
|
@ -52,11 +51,6 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := event.Handler{
|
handler := event.NewHandler(layout)
|
||||||
Layout: layout,
|
|
||||||
RenderEvents: time.NewTicker(console.RenderRate).C,
|
|
||||||
ConsoleEvents: ui.PollEvents(),
|
|
||||||
}
|
|
||||||
|
|
||||||
handler.HandleEvents()
|
handler.HandleEvents()
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,12 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Component struct {
|
type Component struct {
|
||||||
Drawable ui.Drawable
|
Type config.ComponentType
|
||||||
Title string
|
Drawable ui.Drawable
|
||||||
Position config.Position
|
Title string
|
||||||
Size config.Size
|
Position config.Position
|
||||||
Type config.ComponentType
|
Size config.Size
|
||||||
|
RefreshRateMs int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Component) Move(x, y int) {
|
func (c *Component) Move(x, y int) {
|
||||||
|
|
|
@ -9,10 +9,11 @@ import (
|
||||||
|
|
||||||
type Layout struct {
|
type Layout struct {
|
||||||
ui.Block
|
ui.Block
|
||||||
Components []Component
|
Components []Component
|
||||||
menu *Menu
|
ChangeModeEvents chan Mode
|
||||||
mode Mode
|
mode Mode
|
||||||
selection int
|
menu *Menu
|
||||||
|
selection int
|
||||||
}
|
}
|
||||||
|
|
||||||
type Mode rune
|
type Mode rune
|
||||||
|
@ -37,16 +38,17 @@ func NewLayout(width, height int, menu *Menu) *Layout {
|
||||||
block.SetRect(0, 0, width, height)
|
block.SetRect(0, 0, width, height)
|
||||||
|
|
||||||
return &Layout{
|
return &Layout{
|
||||||
Block: block,
|
Block: block,
|
||||||
Components: make([]Component, 0),
|
Components: make([]Component, 0),
|
||||||
menu: menu,
|
menu: menu,
|
||||||
mode: ModeDefault,
|
mode: ModeDefault,
|
||||||
selection: 0,
|
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) {
|
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{drawable, title, position, size, Type})
|
l.Components = append(l.Components, Component{Type, drawable, title, position, size, refreshRateMs})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Layout) GetComponents(Type config.ComponentType) []ui.Drawable {
|
func (l *Layout) GetComponents(Type config.ComponentType) []ui.Drawable {
|
||||||
|
@ -62,36 +64,41 @@ func (l *Layout) GetComponents(Type config.ComponentType) []ui.Drawable {
|
||||||
return components
|
return components
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *Layout) changeMode(m Mode) {
|
||||||
|
l.mode = m
|
||||||
|
l.ChangeModeEvents <- m
|
||||||
|
}
|
||||||
|
|
||||||
func (l *Layout) HandleConsoleEvent(e string) {
|
func (l *Layout) HandleConsoleEvent(e string) {
|
||||||
switch e {
|
switch e {
|
||||||
case console.KeyEnter:
|
case console.KeyEnter:
|
||||||
switch l.mode {
|
switch l.mode {
|
||||||
case ModeComponentSelect:
|
case ModeComponentSelect:
|
||||||
l.menu.choose()
|
l.menu.choose()
|
||||||
l.mode = ModeMenuOptionSelect
|
l.changeMode(ModeMenuOptionSelect)
|
||||||
case ModeMenuOptionSelect:
|
case ModeMenuOptionSelect:
|
||||||
option := l.menu.getSelectedOption()
|
option := l.menu.getSelectedOption()
|
||||||
switch option {
|
switch option {
|
||||||
case MenuOptionMove:
|
case MenuOptionMove:
|
||||||
l.mode = ModeComponentMove
|
l.changeMode(ModeComponentMove)
|
||||||
l.menu.moveOrResize()
|
l.menu.moveOrResize()
|
||||||
case MenuOptionResize:
|
case MenuOptionResize:
|
||||||
l.mode = ModeComponentResize
|
l.changeMode(ModeComponentResize)
|
||||||
l.menu.moveOrResize()
|
l.menu.moveOrResize()
|
||||||
case MenuOptionPinpoint:
|
case MenuOptionPinpoint:
|
||||||
l.mode = ModeChartPinpoint
|
l.changeMode(ModeChartPinpoint)
|
||||||
l.menu.idle()
|
l.menu.idle()
|
||||||
chart := l.getSelectedComponent().Drawable.(*runchart.RunChart)
|
chart := l.getSelectedComponent().Drawable.(*runchart.RunChart)
|
||||||
chart.MoveSelection(0)
|
chart.MoveSelection(0)
|
||||||
case MenuOptionResume:
|
case MenuOptionResume:
|
||||||
l.mode = ModeDefault
|
l.changeMode(ModeDefault)
|
||||||
l.menu.idle()
|
l.menu.idle()
|
||||||
}
|
}
|
||||||
case ModeComponentMove:
|
case ModeComponentMove:
|
||||||
fallthrough
|
fallthrough
|
||||||
case ModeComponentResize:
|
case ModeComponentResize:
|
||||||
l.menu.idle()
|
l.menu.idle()
|
||||||
l.mode = ModeDefault
|
l.changeMode(ModeDefault)
|
||||||
}
|
}
|
||||||
case console.KeyEsc:
|
case console.KeyEsc:
|
||||||
switch l.mode {
|
switch l.mode {
|
||||||
|
@ -103,12 +110,12 @@ func (l *Layout) HandleConsoleEvent(e string) {
|
||||||
fallthrough
|
fallthrough
|
||||||
case ModeMenuOptionSelect:
|
case ModeMenuOptionSelect:
|
||||||
l.menu.idle()
|
l.menu.idle()
|
||||||
l.mode = ModeDefault
|
l.changeMode(ModeDefault)
|
||||||
}
|
}
|
||||||
case console.KeyLeft:
|
case console.KeyLeft:
|
||||||
switch l.mode {
|
switch l.mode {
|
||||||
case ModeDefault:
|
case ModeDefault:
|
||||||
l.mode = ModeComponentSelect
|
l.changeMode(ModeComponentSelect)
|
||||||
l.selection = 0
|
l.selection = 0
|
||||||
l.menu.highlight(l.getComponent(l.selection))
|
l.menu.highlight(l.getComponent(l.selection))
|
||||||
case ModeChartPinpoint:
|
case ModeChartPinpoint:
|
||||||
|
@ -127,7 +134,7 @@ func (l *Layout) HandleConsoleEvent(e string) {
|
||||||
case console.KeyRight:
|
case console.KeyRight:
|
||||||
switch l.mode {
|
switch l.mode {
|
||||||
case ModeDefault:
|
case ModeDefault:
|
||||||
l.mode = ModeComponentSelect
|
l.changeMode(ModeComponentSelect)
|
||||||
l.selection = 0
|
l.selection = 0
|
||||||
l.menu.highlight(l.getComponent(l.selection))
|
l.menu.highlight(l.getComponent(l.selection))
|
||||||
case ModeChartPinpoint:
|
case ModeChartPinpoint:
|
||||||
|
@ -146,7 +153,7 @@ func (l *Layout) HandleConsoleEvent(e string) {
|
||||||
case console.KeyUp:
|
case console.KeyUp:
|
||||||
switch l.mode {
|
switch l.mode {
|
||||||
case ModeDefault:
|
case ModeDefault:
|
||||||
l.mode = ModeComponentSelect
|
l.changeMode(ModeComponentSelect)
|
||||||
l.selection = 0
|
l.selection = 0
|
||||||
l.menu.highlight(l.getComponent(l.selection))
|
l.menu.highlight(l.getComponent(l.selection))
|
||||||
case ModeComponentSelect:
|
case ModeComponentSelect:
|
||||||
|
@ -164,7 +171,7 @@ func (l *Layout) HandleConsoleEvent(e string) {
|
||||||
case console.KeyDown:
|
case console.KeyDown:
|
||||||
switch l.mode {
|
switch l.mode {
|
||||||
case ModeDefault:
|
case ModeDefault:
|
||||||
l.mode = ModeComponentSelect
|
l.changeMode(ModeComponentSelect)
|
||||||
l.selection = 0
|
l.selection = 0
|
||||||
l.menu.highlight(l.getComponent(l.selection))
|
l.menu.highlight(l.getComponent(l.selection))
|
||||||
case ModeComponentSelect:
|
case ModeComponentSelect:
|
||||||
|
|
Loading…
Reference in New Issue