[GH-ISSUE #174] Bug in the linechart #104

Closed
opened 2026-03-03 16:22:24 +03:00 by kerem · 9 comments
Owner

Originally created by @keithknott26 on GitHub (Mar 19, 2019).
Original GitHub issue: https://github.com/mum4k/termdash/issues/174

Hello,

I have been experiencing an intermittent problem where the linechart panics but have been unable to reproduce it with any certainty. I found today I was lucky enough to recreate the issue over and over again by cycling through the same dataset.

I have not tried this on its own because I suspect the bug has to do with the widths of the linecharts and perhaps that empty cell at the end of the chart?

Here's what I have so far:

Initialize the Linechart:

lc, err = linechart.New(
			linechart.AxesCellOpts(cell.FgColor(cell.ColorNumber(graphAxes))),
			linechart.YLabelCellOpts(cell.FgColor(cell.ColorNumber(graphYLabels))),
			linechart.XLabelCellOpts(cell.FgColor(cell.ColorNumber(graphXLabels))),
		)
Series Data (1500 0's):

inputs = [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]

if err := lc.Series("first", inputs,
		linechart.SeriesCellOpts(cell.FgColor(cell.ColorNumber(GraphLine))),
	); err != nil {
		fmt.Println("LineChart Error:", err)
	}

graphWidth = lc.ValueCapacity() //this returns 44
inputsOne = c.SeriesOne.Last(graphWidth)
//inputsOne overwritten to static dataset

inputsOne = []float64{1, 2, 4, 3, 5, 6, 7, 8, 9, 10, 11, 12, 10, 9, 10, 9, 8, 9, 10, 11, 12, 13, 14, 14, 14, 13, 13, 14, 16, 14, 15, 15, 13, 11, 12, 12, 12, 10, 7, 7, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
inputLabels = []string{"19:20:58", "19:20:59", "19:21:00", "19:21:01"}
for i, x := range inputLabels {
			labelMapOne[i] = x
}

Then a periodic loop expires and this code gets run again, it's on the 3rd loop that the panic occurs:

2019/03/18 19:10:54 Chart: Event Delivery - Active Threads inputsOne = [1 2 4 3 5 6 7 8 9 10 11 12 10 9 10 9 8 9 10 11 12 13 14 14 14 13 13 14 16 14 15 15 13 11 12 12 12 10 7 7 3 3 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]
2019/03/18 19:10:54 Chart: Event Delivery - Active Threads inputsTwo = []
2019/03/18 19:10:54 Chart: Event Delivery - Active Threads Labels = map[]

➜  cmd git:(master) ✗ go run dashboard.go

panic: container.Draw => error: unable to draw widget *linechart.LineChart: failure for series first[0], yd.Scale.ValueToPixel => position 120 out of bounds 0 <= pos <= 15

goroutine 1 [running]:
main.main()
	/Users/keithknott/go/src/github.com/keithknott26/adlDashboard/cmd/dashboard.go:1020 +0x806
exit status 2

I found I'm able to avoid the panic by populating a smaller amount of entries in inputsOne. It's a bug that happens maybe every hour or so and crashes the app, it seems to happen more frequently when I have graphs with multiple series (3 or more) but has happened infrequently on single series linecharts.

I'm wondering if there might be a way I can recover from the panic as a workaround and have the app still function? I will keep trying to find ways to reproduce this issue in the meantime.

Originally created by @keithknott26 on GitHub (Mar 19, 2019). Original GitHub issue: https://github.com/mum4k/termdash/issues/174 Hello, I have been experiencing an intermittent problem where the linechart panics but have been unable to reproduce it with any certainty. I found today I was lucky enough to recreate the issue over and over again by cycling through the same dataset. I have not tried this on its own because I suspect the bug has to do with the widths of the linecharts and perhaps that empty cell at the end of the chart? Here's what I have so far: Initialize the Linechart: ``` lc, err = linechart.New( linechart.AxesCellOpts(cell.FgColor(cell.ColorNumber(graphAxes))), linechart.YLabelCellOpts(cell.FgColor(cell.ColorNumber(graphYLabels))), linechart.XLabelCellOpts(cell.FgColor(cell.ColorNumber(graphXLabels))), ) Series Data (1500 0's): inputs = [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] if err := lc.Series("first", inputs, linechart.SeriesCellOpts(cell.FgColor(cell.ColorNumber(GraphLine))), ); err != nil { fmt.Println("LineChart Error:", err) } graphWidth = lc.ValueCapacity() //this returns 44 inputsOne = c.SeriesOne.Last(graphWidth) //inputsOne overwritten to static dataset inputsOne = []float64{1, 2, 4, 3, 5, 6, 7, 8, 9, 10, 11, 12, 10, 9, 10, 9, 8, 9, 10, 11, 12, 13, 14, 14, 14, 13, 13, 14, 16, 14, 15, 15, 13, 11, 12, 12, 12, 10, 7, 7, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} inputLabels = []string{"19:20:58", "19:20:59", "19:21:00", "19:21:01"} for i, x := range inputLabels { labelMapOne[i] = x } ``` Then a periodic loop expires and this code gets run again, it's on the 3rd loop that the panic occurs: ``` 2019/03/18 19:10:54 Chart: Event Delivery - Active Threads inputsOne = [1 2 4 3 5 6 7 8 9 10 11 12 10 9 10 9 8 9 10 11 12 13 14 14 14 13 13 14 16 14 15 15 13 11 12 12 12 10 7 7 3 3 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1] 2019/03/18 19:10:54 Chart: Event Delivery - Active Threads inputsTwo = [] 2019/03/18 19:10:54 Chart: Event Delivery - Active Threads Labels = map[] ➜ cmd git:(master) ✗ go run dashboard.go panic: container.Draw => error: unable to draw widget *linechart.LineChart: failure for series first[0], yd.Scale.ValueToPixel => position 120 out of bounds 0 <= pos <= 15 goroutine 1 [running]: main.main() /Users/keithknott/go/src/github.com/keithknott26/adlDashboard/cmd/dashboard.go:1020 +0x806 exit status 2 ``` I found I'm able to avoid the panic by populating a smaller amount of entries in inputsOne. It's a bug that happens maybe every hour or so and crashes the app, it seems to happen more frequently when I have graphs with multiple series (3 or more) but has happened infrequently on single series linecharts. I'm wondering if there might be a way I can recover from the panic as a workaround and have the app still function? I will keep trying to find ways to reproduce this issue in the meantime.
kerem 2026-03-03 16:22:24 +03:00
  • closed this issue
  • added the
    bug
    label
Author
Owner

@keithknott26 commented on GitHub (Mar 19, 2019):

Also wanted to know if you knew of anything that might cause this issue aside from a bug, I’ve been over the code a number of times and the labels and values are clean. Perhaps the next step is for me to reproduce this outside of the app in a single chart using the linechart demo

<!-- gh-comment-id:474204195 --> @keithknott26 commented on GitHub (Mar 19, 2019): Also wanted to know if you knew of anything that might cause this issue aside from a bug, I’ve been over the code a number of times and the labels and values are clean. Perhaps the next step is for me to reproduce this outside of the app in a single chart using the linechart demo
Author
Owner

@keithknott26 commented on GitHub (Mar 20, 2019):

Hello,

A bit more info on this, I found that it doesn't matter whether or not XUnscaled() is enabled or not. I was able to capture a panic from both on/off scenarios where the failure was reported in the same position 36 out of bounds 0 <= pos <= 35 with different data. The panic appears to be caused when I set the labelMap.

Hopefully this helps, if there's anything specific you wanted me to try and dump to the log let me know.

Error: panic: container.Draw => error: unable to draw widget *linechart.LineChart: failure for series first0[1], yd.Scale.ValueToPixel => position 36 out of bounds 0 <= pos <= 35

2019/03/19 19:31:40 BTM Chart ID: 0 Label        			------> Alert Activity (sec)- Grn: Inserts | Yel: Results | Pnk: Terminates
2019/03/19 19:31:40 BTM Chart ID: 0 Xunscaled      			------> true
2019/03/19 19:31:40 BTM Chart ID: 0 LC ValueCapacity		------> 114
2019/03/19 19:31:40 BTM Chart ID: 0 Chart Props: 			------> &{{{0 0} 0 0 0 0} map[first-0:0xc0000b2460 first0:0xc0048961e0 second0:0xc004896230 third0:0xc0048962d0] 0 15.300938733333332 114 0xc00029a080 map[0:19:31:19 1:19:31:20 2:19:31:21 3:19:31:22 4:19:31:23 5:19:31:24 6:19:31:25 7:19:31:26 8:19:31:27 9:19:31:28 10:19:31:29 11:19:31:30 12:19:31:31 13:19:31:32 14:19:31:33 15:19:31:34 16:19:31:35 17:19:31:36 18:19:31:37 19:19:31:38] 0xc0005dd8f0}

inputs["one"] = [15.300938733333332 15.067662566666666 14.8342849 14.600990300000001 14.367653 14.134312900000001 13.901014333333334 14.667553366666667 14.434269500000001 14.2008685 13.967639933333334 13.7343192 13.500966033333334 13.267614966666667 14.034252233333333 14.800873866666667 14.566988933333333 14.3342807 14.100948533333334 14.867604233333333]
inputs["two"] = [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
inputs["three"] = [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]

------------------------------------------------------------------

Error: panic: container.Draw => error: unable to draw widget *linechart.LineChart: failure for series third0[0], yd.Scale.ValueToPixel => position 36 out of bounds 0 <= pos <= 35

2019/03/19 19:53:47 BTM Chart ID: 0 Label        			------> Alert Activity (sec)- Grn: Inserts | Yel: Results | Pnk: Terminates
2019/03/19 19:53:47 BTM Chart ID: 0 Xunscaled      			------> false
2019/03/19 19:53:47 BTM Chart ID: 0  LC ValueCapacity     	------> 114

2019/03/19 19:53:47 BTM Chart ID: 0 Chart Props: 			------> &{{{0 0} 0 0 0 0} map[first-0:0xc0000ca460 first0:0xc00a0cec80 second0:0xc00a0ced20 third0:0xc00a0ced70] 0 37.40138265 114 0xc0002a4080 map[0:19:53:26 1:19:53:27 2:19:53:28 3:19:53:29 4:19:53:30 5:19:53:31 6:19:53:32 7:19:53:33 8:19:53:34 9:19:53:35 10:19:53:36 11:19:53:37 12:19:53:38 13:19:53:39 14:19:53:40 15:19:53:41 16:19:53:42 17:19:53:43 18:19:53:44 19:19:53:45] 0xc0005c78f0}

inputs["one"] = [11.85751225 12.70752125 13.55754705 13.407542549999999 14.257551249999999 15.1075379 14.95753415 14.8074893 15.6574953 16.5073393 16.3574311 17.2072955 17.05754915 16.9074716 16.7573294 16.60756745 16.45743905 16.30753025 16.1572925 16.00744205]

inputs["two"] = [5.778002666666667 6.661326666666667 6.5446820500000005 6.428019466666667 6.311372633333333 6.1946788999999995 7.0780109499999995 6.961308233333334 6.844640283333334 6.727869083333333 6.611251883333334 6.494500166666667 7.37802285 7.2612874666666665 7.144506933333334 8.028052483333333 7.911228783333334 7.79467085 7.677830466666666 8.561265766666667]

inputs["three"] = [27.650853883333333 27.167641383333333 26.684462233333335 28.20114243333333 29.718013550000002 29.234272766666663 30.75110135 32.26747318333334 31.784140333333333 31.3005518 30.817231033333336 31.333645883333332 33.85114436666667 34.36732528333334 33.883561783333334 37.40138265 36.9171595 36.434224433333334 35.9504706 35.467383283333334]
<!-- gh-comment-id:474666217 --> @keithknott26 commented on GitHub (Mar 20, 2019): Hello, A bit more info on this, I found that it doesn't matter whether or not XUnscaled() is enabled or not. I was able to capture a panic from both on/off scenarios where the failure was reported in the same position 36 out of bounds 0 <= pos <= 35 with different data. The panic appears to be caused when I set the labelMap. Hopefully this helps, if there's anything specific you wanted me to try and dump to the log let me know. ``` Error: panic: container.Draw => error: unable to draw widget *linechart.LineChart: failure for series first0[1], yd.Scale.ValueToPixel => position 36 out of bounds 0 <= pos <= 35 2019/03/19 19:31:40 BTM Chart ID: 0 Label ------> Alert Activity (sec)- Grn: Inserts | Yel: Results | Pnk: Terminates 2019/03/19 19:31:40 BTM Chart ID: 0 Xunscaled ------> true 2019/03/19 19:31:40 BTM Chart ID: 0 LC ValueCapacity ------> 114 2019/03/19 19:31:40 BTM Chart ID: 0 Chart Props: ------> &{{{0 0} 0 0 0 0} map[first-0:0xc0000b2460 first0:0xc0048961e0 second0:0xc004896230 third0:0xc0048962d0] 0 15.300938733333332 114 0xc00029a080 map[0:19:31:19 1:19:31:20 2:19:31:21 3:19:31:22 4:19:31:23 5:19:31:24 6:19:31:25 7:19:31:26 8:19:31:27 9:19:31:28 10:19:31:29 11:19:31:30 12:19:31:31 13:19:31:32 14:19:31:33 15:19:31:34 16:19:31:35 17:19:31:36 18:19:31:37 19:19:31:38] 0xc0005dd8f0} inputs["one"] = [15.300938733333332 15.067662566666666 14.8342849 14.600990300000001 14.367653 14.134312900000001 13.901014333333334 14.667553366666667 14.434269500000001 14.2008685 13.967639933333334 13.7343192 13.500966033333334 13.267614966666667 14.034252233333333 14.800873866666667 14.566988933333333 14.3342807 14.100948533333334 14.867604233333333] inputs["two"] = [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] inputs["three"] = [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] ------------------------------------------------------------------ Error: panic: container.Draw => error: unable to draw widget *linechart.LineChart: failure for series third0[0], yd.Scale.ValueToPixel => position 36 out of bounds 0 <= pos <= 35 2019/03/19 19:53:47 BTM Chart ID: 0 Label ------> Alert Activity (sec)- Grn: Inserts | Yel: Results | Pnk: Terminates 2019/03/19 19:53:47 BTM Chart ID: 0 Xunscaled ------> false 2019/03/19 19:53:47 BTM Chart ID: 0 LC ValueCapacity ------> 114 2019/03/19 19:53:47 BTM Chart ID: 0 Chart Props: ------> &{{{0 0} 0 0 0 0} map[first-0:0xc0000ca460 first0:0xc00a0cec80 second0:0xc00a0ced20 third0:0xc00a0ced70] 0 37.40138265 114 0xc0002a4080 map[0:19:53:26 1:19:53:27 2:19:53:28 3:19:53:29 4:19:53:30 5:19:53:31 6:19:53:32 7:19:53:33 8:19:53:34 9:19:53:35 10:19:53:36 11:19:53:37 12:19:53:38 13:19:53:39 14:19:53:40 15:19:53:41 16:19:53:42 17:19:53:43 18:19:53:44 19:19:53:45] 0xc0005c78f0} inputs["one"] = [11.85751225 12.70752125 13.55754705 13.407542549999999 14.257551249999999 15.1075379 14.95753415 14.8074893 15.6574953 16.5073393 16.3574311 17.2072955 17.05754915 16.9074716 16.7573294 16.60756745 16.45743905 16.30753025 16.1572925 16.00744205] inputs["two"] = [5.778002666666667 6.661326666666667 6.5446820500000005 6.428019466666667 6.311372633333333 6.1946788999999995 7.0780109499999995 6.961308233333334 6.844640283333334 6.727869083333333 6.611251883333334 6.494500166666667 7.37802285 7.2612874666666665 7.144506933333334 8.028052483333333 7.911228783333334 7.79467085 7.677830466666666 8.561265766666667] inputs["three"] = [27.650853883333333 27.167641383333333 26.684462233333335 28.20114243333333 29.718013550000002 29.234272766666663 30.75110135 32.26747318333334 31.784140333333333 31.3005518 30.817231033333336 31.333645883333332 33.85114436666667 34.36732528333334 33.883561783333334 37.40138265 36.9171595 36.434224433333334 35.9504706 35.467383283333334] ```
Author
Owner

@mum4k commented on GitHub (Mar 20, 2019):

Thank you @keithknott26, this is a great amount of debugging data and I have a theory of where this bug lives. I will try to reproduce this locally.

I think you also asked if there is a way to avoid the panic and continue instead. I am assuming that you are running using the periodic redraws. If so, you can provide your own error handler which will avoid the panic. Documented here:

https://github.com/mum4k/termdash/wiki/Termdash-API#termdasherrorhandler

Alternatively Termdash shouldn't panic if you're using the triggered redraws.

<!-- gh-comment-id:474667399 --> @mum4k commented on GitHub (Mar 20, 2019): Thank you @keithknott26, this is a great amount of debugging data and I have a theory of where this bug lives. I will try to reproduce this locally. I think you also asked if there is a way to avoid the panic and continue instead. I am assuming that you are running using the periodic redraws. If so, you can provide your own error handler which will avoid the panic. Documented here: https://github.com/mum4k/termdash/wiki/Termdash-API#termdasherrorhandler Alternatively Termdash shouldn't panic if you're using the triggered redraws.
Author
Owner

@mum4k commented on GitHub (Mar 20, 2019):

One thing that could help - if at all possible could you share the full code on your end that you are using to reproduce this panic?

It would help me if I had something ready to reproduce this locally.

<!-- gh-comment-id:474685857 --> @mum4k commented on GitHub (Mar 20, 2019): One thing that could help - if at all possible could you share the full code on your end that you are using to reproduce this panic? It would help me if I had something ready to reproduce this locally.
Author
Owner

@keithknott26 commented on GitHub (Mar 20, 2019):

I'm happy to share the code, it's the data that might be the problem. The dashboard effectively tails a log file and then picks out certain log lines and uses the metrics to build the line chart(s). The thing is, it uses time.Now() when looking at the log line so unless you're tailing the log live you wont be able to reproduce the same scenario. There are something like 14 charts in total but a couple charts in particular expose the problem (the ones which aren't very wide).

I was thinking I could probably come up with a sanitized version of the log file to drive the data stream, but that doesn't solve the time.Now() problem I mentioned above.

I'll continue trying to collect something that will allow us to reproduce this issue. In the meantime I've sent the (largely unfinished) dashboard code to termdash@termdash.com - it expects to tail a file - most of the code you'll care about will be in chart.go starting around like 210

<!-- gh-comment-id:474695739 --> @keithknott26 commented on GitHub (Mar 20, 2019): I'm happy to share the code, it's the data that might be the problem. The dashboard effectively tails a log file and then picks out certain log lines and uses the metrics to build the line chart(s). The thing is, it uses time.Now() when looking at the log line so unless you're tailing the log live you wont be able to reproduce the same scenario. There are something like 14 charts in total but a couple charts in particular expose the problem (the ones which aren't very wide). I was thinking I could probably come up with a sanitized version of the log file to drive the data stream, but that doesn't solve the time.Now() problem I mentioned above. I'll continue trying to collect *something* that will allow us to reproduce this issue. In the meantime I've sent the (largely unfinished) dashboard code to termdash@termdash.com - it expects to tail a file - most of the code you'll care about will be in chart.go starting around like 210
Author
Owner

@mum4k commented on GitHub (Mar 21, 2019):

Thank you @keithknott26, that helped a lot. I have a theory and a proof now, so I believe this one is almost tackled.

Interestingly enough this is again a data race, this time one that is between both datadash and termdash.

Background: as you probably know, a slice in Go is implemented as a pointer to the underlying array that holds the data. That array can sometimes be changed when appending to slice, but that only happens when it runs out of capacity. This article describes it well. Datadash passes a slice to Termdash (via LineChart.Series) and from the above explanation - both Datadash and Termdash then share a pointer to the same memory - the underlying array. To complete the picture, this is where that array gets initiated, it is actually owned by the float64RingBuffer:

github.com/keithknott26/datadash@9ed568bfad/ring.go (L4)

Here's what's happening:

  1. Datadash passes the slice (pointer to the array) to Termdash by calling LineChart.Series. Let's say it passed []float64{0,1,2}
  2. LineChart.Series analyses the samples to establish the minimum and maximum values for the Y axis. Those will be: min: 0, max:2.
  3. LineChart doesn't draw immediately, that happens at the next periodic redraw interval.
  4. Datadash receives new values and stores them in the ring buffer, if it is over capacity, it rotates the data in the slice, reusing the same array:

github.com/keithknott26/datadash@9ed568bfad/ring.go (L32)

Let's say that it added a new value 3, so the array now is []float64{3,1,2}.

  1. Periodic redraw interval expires and Termdash redraws the screen.
  2. The Linechart draws values one by one, the first one is 3, while the maximum on the Y axis is 2. This causes the error you observed.

I have been discussing with myself whether this should be fixed in Datadash or Termdash. I feel that this behavior makes the API of the widgets brittle, since it is easy to make this mistake.

So I will push a fix inside Termdash that will ensure the widgets store a deep copy of the data passed in so they never share a pointer to the same memory with the caller. This might one day bite us if the performance of those copies becomes noticeable, but I think we are fine for now.

<!-- gh-comment-id:475097586 --> @mum4k commented on GitHub (Mar 21, 2019): Thank you @keithknott26, that helped a lot. I have a theory and a proof now, so I believe this one is almost tackled. Interestingly enough this is again a data race, this time one that is between both datadash and termdash. **Background:** as you probably know, a slice in Go is implemented as a pointer to the underlying array that holds the data. That array can sometimes be changed when appending to slice, but that only happens when it runs out of capacity. [This article](https://blog.golang.org/go-slices-usage-and-internals) describes it well. Datadash passes a slice to Termdash (via LineChart.Series) and from the above explanation - both Datadash and Termdash then share a pointer to the same memory - the underlying array. To complete the picture, this is where that array gets initiated, it is actually owned by the float64RingBuffer: https://github.com/keithknott26/datadash/blob/9ed568bfadfeba85dfb0f3d1e44a7d412fcd5ef3/ring.go#L4 Here's what's happening: 1. Datadash passes the slice (pointer to the array) to Termdash by calling LineChart.Series. Let's say it passed **[]float64{0,1,2}** 1. LineChart.Series analyses the samples to establish the minimum and maximum values for the Y axis. Those will be: **min: 0, max:2**. 1. LineChart doesn't draw immediately, that happens at the next periodic redraw interval. 1. Datadash receives new values and stores them in the ring buffer, if it is over capacity, it rotates the data in the slice, reusing the same array: https://github.com/keithknott26/datadash/blob/9ed568bfadfeba85dfb0f3d1e44a7d412fcd5ef3/ring.go#L32 Let's say that it added a new value **3**, so the array now is **[]float64{3,1,2}**. 5. Periodic redraw interval expires and Termdash redraws the screen. 6. The Linechart draws values one by one, the first one is **3**, while the maximum on the Y axis is **2**. This causes the error you observed. I have been discussing with myself whether this should be fixed in Datadash or Termdash. I feel that this behavior makes the API of the widgets brittle, since it is easy to make this mistake. So I will push a fix inside Termdash that will ensure the widgets store a deep copy of the data passed in so they never share a pointer to the same memory with the caller. This might one day bite us if the performance of those copies becomes noticeable, but I think we are fine for now.
Author
Owner

@mum4k commented on GitHub (Mar 21, 2019):

@keithknott26, the fix has been merged into the devel branch. I would appreciate if you could confirm that this works or reopen this issue if it reoccurs.

I have also improved the error messages with additional data, so if it happens again, please do paste the new (more complete) errors.

<!-- gh-comment-id:475105171 --> @mum4k commented on GitHub (Mar 21, 2019): @keithknott26, the fix has been merged into the devel branch. I would appreciate if you could confirm that this works or reopen this issue if it reoccurs. I have also improved the error messages with additional data, so if it happens again, please do paste the new (more complete) errors.
Author
Owner

@keithknott26 commented on GitHub (Mar 21, 2019):

Thank you for looking into this! I've confirmed this hasn't come up again after 3 hours of running about 20 or so charts. I'm planning to convert the app to use the controller based redraws this weekend, I really appreciate your help in getting this sorted

<!-- gh-comment-id:475147392 --> @keithknott26 commented on GitHub (Mar 21, 2019): Thank you for looking into this! I've confirmed this hasn't come up again after 3 hours of running about 20 or so charts. I'm planning to convert the app to use the controller based redraws this weekend, I really appreciate your help in getting this sorted
Author
Owner

@mum4k commented on GitHub (Mar 21, 2019):

Of course, I am glad to hear that we have successfully tackled this one.

<!-- gh-comment-id:475395562 --> @mum4k commented on GitHub (Mar 21, 2019): Of course, I am glad to hear that we have successfully tackled this one.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/termdash#104
No description provided.