htop
htop copied to clipboard
(Experimental) Improved bar meter drawing algorithm
The improvements are better described with example plotting rather than in words.
Test data:
53: 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.50
54: 0.57 0 0 0 0 0 0 0
679: 0.01 0.48 0.01 0.01 0.48 0.01 0 0
682: 0.50 0 0 0 0 0 0 0
689: 0.50 0.01 0.01 0.01 0.01 0.01 0.01 0.01
690: 1.00 0 0 0 0 0 0 0
697: 0.93 0.01 0.01 0.01 0.01 0.01 0.01 0.01
698: 0.07 0.07 0.07 0.07 0.07 0.07 0.07 0.07
741: 0.07 0.07 0.07 0.07 0.07 0.07 0.07 0.50
Original algorithm:
53: [|#*@$%&.......... ]
54: [|||||||||||| ]
679: [|##########*@$$$$$$$$$$%]
682: [|||||||||| ]
689: [||||||||||#*@$%&. ]
690: [||||||||||||||||||||]
697: [|||||||||||||||||||#*@$%&.]
698: [||##**@@$$%%&&.. ]
741: [||##**@@$$%%&&..........]
New algorithm:
53: [|#*@$%&....... ]
54: [||||||||||| ]
679: [|########*@$$$$$$$$%]
682: [|||||||||| ]
689: [|||||||#*@$%&. ]
690: [||||||||||||||||||||]
697: [|||||||||||||#*@$%&.]
698: [|##*@@$%&&. ]
741: [|##*@@$%&&..........]
Note: You may obtain test data and code in my public gist: https://gist.github.com/Explorer09/45368b8759bc5a1af909 (I have prepared LOTS of data, for testing and debugging :) )
Some main design goals of the new algorithm:
- Every non-zero values shall be seen on the bar, with at least one character.
- No overflow unless the sum of original values exceeds 100%, or when the number of non-zero items exceeds the meter width.
- Except for plotting very small values, all other values, as well as empty space, shall maintain proportion as much as possible on display.
- Linear time.
As a bonus feature, this bar meter is now able to show overflow using the color on the ending ']' character. (Probably won't work in monochrome, sorry.)
Interesting! But what motivated this patch? Have you ever seen it overflow like that in actual use?
The new algorithm is linear (but 3n versus the original n; in any case the n is low, so it would be nice to see if the performance difference is measurable at all) and adds quite a bit of code (I look at code size in terms of memory footprint, surface size for possible bugs and, most importantly, long-term maintenance costs).
If one would revise the algorithm, it's interesting to thing that the goal "Every non-zero values shall be seen on the bar, with at least one character" conflicts with another possible goal, that "the length of the bar should be a fair representation of the total sum".
For things such as CPU%, visualizing the total use is 50%~55% is more useful than knowing that there is <= 5% of guest use, <= 5% of io-wait, etc. The old algorithm shows the "689" case (a 50.7% total) as indistinguishable from one with 85% total, the new one makes it indistinguishable from one with 70% total, with less precision for the greatest (and therefore most important?) value.
This is an interesting topic without a perfect solution, so it's worth discussing!
2016-03-18 Update: Revised! I tweaked the code a little bit the text buffer gets one more space to print when the bar is too small. :) Also removed the useless barOffset variable.

@hishamhm My motivation was not about the CPU, but about an experimental clock meter that I was privately working on. And it annoyed me when the current bar created many rounding errors. That's why I try to write a better bar algorithm.
If you have checked out my gist, you could see I was trying such problem in cases 425 to 677. Yes, I know there's no perfect solution, but I was trying to make it the best that I could. :)
(And by the way, I know that if I make the algorithm n*log(n), it will be even less likely to be accepted.)
@Explorer09 I'd rather not overflow the "]" like that. It's a matter of personal preference, I know, but super narrow terminals like this are a pathological case and I don't think it's worth to have any extra code for that.
Arguably the most important use cases for the bar mode are CPU and memory, so if we're going to improve the algorithm I think their needs should be considered first.
I think I see what you're going after with 425 to 677 (and the problems it has in the original algorithm), but I still think that the best improvement to avoid overflows is to drop the "Every non-zero values shall be seen on the bar, with at least one character" rule altogether. I think it will produce better view of the totals and allow 425-677 to work properly with less hassle/code.
UPDATE: The commit is merged. Old comment kept for reference:
I cherry-picked a minor improvement out of this. bar-tweaks branch, commit 432534b. This doesn't change the behavior (unlike bar-algorithm-new branch) and may be merged without too much discussion. Shall I make a separate pull request with this?
hishamhm
I think I see what you're going after with 425 to 677 (and the problems it has in the original algorithm), but I still think that the best improvement to avoid overflows is to drop the "Every non-zero values shall be seen on the bar, with at least one character" rule altogether. I think it will produce better view of the totals and allow 425-677 to work properly with less hassle/code.
If this htop-bar4 example is what you mean...
53: [*.......... ]
679: [##########$$$$$$$$$$]
689: [||||||||||@ ]
697: [|||||||||||||||||||%]
Yes! It produces a much more realistic representation of the most significant values (the total and the top contributors). I noticed that the rounding artifacts are still there in size 10 for 425-677 but they go away for size 20, which I believe is good enough for practical purposes.