Skip to content

Instantly share code, notes, and snippets.

@Explorer09
Last active March 19, 2016 14:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Explorer09/45368b8759bc5a1af909 to your computer and use it in GitHub Desktop.
Save Explorer09/45368b8759bc5a1af909 to your computer and use it in GitHub Desktop.
Test data and code for htop bar meter algorithms.
Test data and code for htop bar meter algorithms.
1. `make && make check`
2. Use your favorite diff tool to compare the results.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
static char BarMeterMode_characters[] = "|#*@$%&.";
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
#ifndef CLAMP
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
#endif
int main(int argc, char *argv[]) {
double values[8];
int width = 20; // in chars
double total = 1.0;
if (argc > 1) {
width = atoi(argv[1]);
}
if (width <= 0) {
exit(1);
}
int line_num;
int blockSizes[10];
while (!feof(stdin)) {
scanf("%d: %lf %lf %lf %lf %lf %lf %lf %lf\n", &line_num,
values, values+1, values+2, values+3,
values+4, values+5, values+6, values+7);
printf("%4d: [", line_num);
// htop's original algorithm
int offset = 0;
for (int i = 0; i < 8; i++) {
double value = values[i];
value = CLAMP(value, 0.0, total);
if (value > 0.0) {
blockSizes[i] = ceil((value/total) * width);
} else {
blockSizes[i] = 0;
}
int nextOffset = offset + blockSizes[i];
// nextOffset = CLAMP(nextOffset, 0, width);
for (int j = offset; j < nextOffset; j++) {
putchar(BarMeterMode_characters[i]);
}
offset = nextOffset;
}
for (int j = offset; j < width; j++) {
putchar(' ');
}
// data >100% check
int is_overflow = 0;
if (values[0]+values[1]+values[2]+values[3]+
values[4]+values[5]+values[6]+values[7] > total) {
is_overflow = 1;
}
printf("]%s\n", is_overflow ? "!" : "");
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
static char BarMeterMode_characters[] = "|#*@$%&.";
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
#ifndef CLAMP
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
#endif
static double values[8];
static int compare(const void *a, const void *b) {
int aVal = *(int *)a;
int bVal = *(int *)b;
if (values[aVal] < values[bVal]) return -1;
if (values[aVal] == values[bVal]) return 0;
if (values[aVal] > values[bVal]) return 1;
}
int main(int argc, char *argv[]) {
int width = 20; // in chars
double total = 1.0;
if (argc > 1) {
width = atoi(argv[1]);
}
if (width <= 0) {
exit(1);
}
int line_num;
int blockSizes[10];
int sortedIndex[10];
while (!feof(stdin)) {
scanf("%d: %lf %lf %lf %lf %lf %lf %lf %lf\n", &line_num,
values, values+1, values+2, values+3,
values+4, values+5, values+6, values+7);
printf("%4d: [", line_num);
// data >100% check
int is_overflow = 0;
if (values[0]+values[1]+values[2]+values[3]+
values[4]+values[5]+values[6]+values[7] > total) {
is_overflow = 1;
}
// Ideal algorithm. Because this involves sorting, it takes at least
// O(n*log(n)+w) time.
for (int i = 0; i < 10; i++) {
sortedIndex[i] = i;
blockSizes[i] = 0;
}
qsort(sortedIndex, 8, sizeof(int), compare);
int widthB = width;
double totalB = total;
for (int i = 0; i < 8; i++) {
if (values[sortedIndex[i]] <= 0.0)
continue;
double value = values[sortedIndex[i]];
// Belong to A if (value / totalB < 1.0 / widthB)
if (value * widthB < totalB) {
blockSizes[sortedIndex[i]] = 1;
totalB -= value;
widthB -= 1;
}
}
int offset = 0;
double plotted = 0.0; // Unit: characters
double plot;
for (int i = 0; i < 8; i++) {
if (values[i] <= 0.0)
continue;
if (blockSizes[i] == 1) {
plot = plotted + 1;
} else {
plot = plotted + (values[i] * widthB / totalB);
}
blockSizes[i] = (int)round(plot) - offset;
plotted = plot;
offset += blockSizes[i];
for (int j = 0; j < blockSizes[i]; j++) {
putchar(BarMeterMode_characters[i]);
}
}
for (int i = offset; i < width; i++) {
putchar(' ');
}
printf("]%s\n", is_overflow ? "!" : "");
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
static char BarMeterMode_characters[] = "|#*@$%&.";
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
#ifndef CLAMP
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
#endif
int main(int argc, char *argv[]) {
double values[8];
int width = 20; // in chars
double total = 1.0;
if (argc > 1) {
width = atoi(argv[1]);
}
if (width <= 0) {
exit(1);
}
int line_num;
int blockSizes[10];
while (!feof(stdin)) {
scanf("%d: %lf %lf %lf %lf %lf %lf %lf %lf\n", &line_num,
values, values+1, values+2, values+3,
values+4, values+5, values+6, values+7);
printf("%4d: [", line_num);
// The ideal algorithm will require sorting and O(n*log(n)+w) time, but
// such precision and rounding is not useful. This version is less
// precise but linear time (O(n+w)) algorithm.
// Pass 1/3: Computes itemWidth (maximum number of characters that can
// be plotted per item)
int itemWidth = width + 1;
for (int i = 0; i < 8; i++) {
blockSizes[i] = 0;
if (values[i] > 0.0) {
itemWidth--;
}
}
// Pass 2/3: Distributes items into A (very small), B (small) and C
// (larger values) buckets.
int countA = 0, countB = 0;
double totalA = 0.0, totalB = 0.0;
for (int i = 0; i < 8; i++) {
if (values[i] <= 0.0)
continue;
// Belongs to A if (width <= 0 || values[i] / total <= 1.0 / width)
if (values[i] * width <= total) {
blockSizes[i] = 1;
countA++;
totalA += values[i];
continue;
}
// Belongs to B if (values[i] / total < 1.0 / itemWidth)
if (values[i] * itemWidth < total) {
blockSizes[i] = 2;
countB++;
totalB += values[i];
}
// Belongs to C otherwise
}
// assert(width <= 0 || totalB * width > total * countB);
// If there are more space that can be plotted for B, let widthB be
// this additional space.
double widthB = 0.0;
if ((double)countB * (total - totalA) < totalB * (width - countA)) {
widthB = (totalB * (width - countA) / (total - totalA)) - countB;
}
double widthC = (double)(width - countA - countB) - widthB;
double totalC = total - totalA - totalB;
// Pass 3/3: Plot.
int offset = 0;
double plotted = 0.0; // Unit: characters
double plot;
for (int i = 0; i < 8; i++) {
if (values[i] <= 0.0)
continue;
if (blockSizes[i] == 1) {
// A: Always plotted as 1 character
plot = plotted + 1.0;
} else if (blockSizes[i] == 2) {
// B: 1 or 2 characters
plot = plotted + 1.0;
if (widthB > 0.0) {
plot += widthB * (values[i] * width - total) /
(totalB * width - total * countB);
}
} else {
// C: More than 1 character
plot = plotted + (values[i] * widthC / totalC);
}
blockSizes[i] = (int)round(plot) - offset;
plotted = plot;
offset += blockSizes[i];
for (int j = 0; j < blockSizes[i]; j++) {
putchar(BarMeterMode_characters[i]);
}
}
for (int i = offset; i < width; i++) {
putchar(' ');
}
// data >100% check
int is_overflow = 0;
if (values[0]+values[1]+values[2]+values[3]+
values[4]+values[5]+values[6]+values[7] > total) {
is_overflow = 1;
}
printf("]%s\n", is_overflow ? "!" : "");
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
static char BarMeterMode_characters[] = "|#*@$%&.";
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
#ifndef CLAMP
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
#endif
int main(int argc, char *argv[]) {
double values[8];
int width = 20; // in chars
double total = 1.0;
if (argc > 1) {
width = atoi(argv[1]);
}
if (width <= 0) {
exit(1);
}
int line_num;
int blockSizes[10];
while (!feof(stdin)) {
scanf("%d: %lf %lf %lf %lf %lf %lf %lf %lf\n", &line_num,
values, values+1, values+2, values+3,
values+4, values+5, values+6, values+7);
printf("%4d: [", line_num);
#if 0
// The ideal algorithm will require sorting and O(n*log(n)+w) time, but
// such precision and rounding is not useful. This version is less
// precise but linear time (O(n+w)) algorithm.
// Pass 1/3: Computes itemWidth (maximum number of characters that can
// be plotted per item)
int itemWidth = width + 1;
for (int i = 0; i < 8; i++) {
blockSizes[i] = 0;
if (values[i] > 0.0) {
itemWidth--;
}
}
// Pass 2/3: Distributes items into A (very small), B (small) and C
// (larger values) buckets.
int countA = 0, countB = 0;
double totalA = 0.0, totalB = 0.0;
for (int i = 0; i < 8; i++) {
if (values[i] <= 0.0)
continue;
// Belongs to A if (width <= 0 || values[i] / total <= 1.0 / width)
if (values[i] * width <= total) {
blockSizes[i] = 1;
countA++;
totalA += values[i];
continue;
}
// Belongs to B if (values[i] / total < 1.0 / itemWidth)
if (values[i] * itemWidth < total) {
blockSizes[i] = 2;
countB++;
totalB += values[i];
}
// Belongs to C otherwise
}
// assert(width <= 0 || totalB * width > total * countB);
// If there are more space that can be plotted for B, let widthB be
// this additional space.
double widthB = 0.0;
if ((double)countB * (total - totalA) < totalB * (width - countA)) {
widthB = (totalB * (width - countA) / (total - totalA)) - countB;
}
double widthC = (double)(width - countA - countB) - widthB;
double totalC = total - totalA - totalB;
#endif
double widthC = width;
double totalC = total;
// Pass 3/3: Plot.
int offset = 0;
double plotted = 0.0; // Unit: characters
double plot;
for (int i = 0; i < 8; i++) {
if (values[i] <= 0.0)
continue;
#if 0
if (blockSizes[i] == 1) {
// A: Always plotted as 1 character
plot = plotted + 1.0;
} else if (blockSizes[i] == 2) {
// B: 1 or 2 characters
plot = plotted + 1.0;
if (widthB > 0.0) {
plot += widthB * (values[i] * width - total) /
(totalB * width - total * countB);
}
} else
#endif
{
// C: More than 1 character
plot = plotted + (values[i] * widthC / totalC);
}
blockSizes[i] = (int)round(plot) - offset;
plotted = plot;
offset += blockSizes[i];
for (int j = 0; j < blockSizes[i]; j++) {
putchar(BarMeterMode_characters[i]);
}
}
for (int i = offset; i < width; i++) {
putchar(' ');
}
// data >100% check
int is_overflow = 0;
if (values[0]+values[1]+values[2]+values[3]+
values[4]+values[5]+values[6]+values[7] > total) {
is_overflow = 1;
}
printf("]%s\n", is_overflow ? "!" : "");
}
return 0;
}
CC = gcc -std=gnu99
LIBS = -lm
.PHONY: all check clean
all: htop-bar1 htop-bar2 htop-bar3 htop-bar4
htop-bar1: htop-bar1.c
htop-bar2: htop-bar2.c
htop-bar3: htop-bar3.c
htop-bar4: htop-bar4.c
.c:
$(CC) -o $@ $< $(LIBS)
test_data.txt: test_data.sh
bash test_data.sh >test_data.txt
check: htop-bar1 htop-bar2 htop-bar3 test_data.txt
./htop-bar1 5 <test_data.txt >htop-bar1-w5.out
./htop-bar1 10 <test_data.txt >htop-bar1-w10.out
./htop-bar1 20 <test_data.txt >htop-bar1-w20.out
./htop-bar2 5 <test_data.txt >htop-bar2-w5.out
./htop-bar2 10 <test_data.txt >htop-bar2-w10.out
./htop-bar2 20 <test_data.txt >htop-bar2-w20.out
./htop-bar3 5 <test_data.txt >htop-bar3-w5.out
./htop-bar3 10 <test_data.txt >htop-bar3-w10.out
./htop-bar3 20 <test_data.txt >htop-bar3-w20.out
./htop-bar4 5 <test_data.txt >htop-bar4-w5.out
./htop-bar4 10 <test_data.txt >htop-bar4-w10.out
./htop-bar4 20 <test_data.txt >htop-bar4-w20.out
clean:
rm -f htop-bar1 htop-bar2 htop-bar3 htop-bar4
rm -f test_data.txt
rm -f htop-bar1-w5.out htop-bar1-w10.out htop-bar1-w20.out
rm -f htop-bar2-w5.out htop-bar2-w10.out htop-bar2-w20.out
rm -f htop-bar3-w5.out htop-bar3-w10.out htop-bar3-w20.out
rm -f htop-bar4-w5.out htop-bar4-w10.out htop-bar4-w20.out
#!/bin/bash
line_num=1
for (( i=0 ; i<=13 ; i++ )) do
for (( j=25 ; j<=75 ; j+=25 )) do
printf '%4d: 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d\n' \
$line_num $i $i $i $i $i $i $i $i
line_num=$((line_num+1))
printf '%4d: 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d\n' \
$line_num $j $i $i $i $i $i $i $i
line_num=$((line_num+1))
printf '%4d: 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d\n' \
$line_num $i $j $i $i $i $i $i $i
line_num=$((line_num+1))
printf '%4d: 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d\n' \
$line_num $i $i $j $i $i $i $i $i
line_num=$((line_num+1))
printf '%4d: 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d\n' \
$line_num $i $i $i $j $i $i $i $i
line_num=$((line_num+1))
printf '%4d: 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d\n' \
$line_num $i $i $i $i $j $i $i $i
line_num=$((line_num+1))
printf '%4d: 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d\n' \
$line_num $i $i $i $i $i $j $i $i
line_num=$((line_num+1))
printf '%4d: 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d\n' \
$line_num $i $i $i $i $i $i $j $i
line_num=$((line_num+1))
printf '%4d: 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d 0.%02d\n' \
$line_num $i $i $i $i $i $i $i $j
line_num=$((line_num+1))
if [ $(($i*7+$j)) -lt 100 ]; then
printf '%4d: 0.%02d 0.00 0.00 0.00 0.00 0.00 0.00 0.00\n' $line_num $((i*7+j))
line_num=$((line_num+1))
printf '%4d: 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.%02d\n' $line_num $((i*7+j))
line_num=$((line_num+1))
fi
done
done
for i in 25 50 75 99 ; do
for (( j=0 ; j<=i ; j++ )) do
printf '%4d: 0.%02d 0.%02d 0.00 0.00 0.00 0.00 0.00 0.00\n' \
$line_num $j $((i-j))
line_num=$((line_num+1))
done
done
printf '%4d: 0.01 0.48 0.01 0.00 0.00 0.00 0.00 0.00\n' $line_num
line_num=$((line_num+1))
printf '%4d: 0.01 0.48 0.01 0.01 0.48 0.01 0.00 0.00\n' $line_num
line_num=$((line_num+1))
printf '%4d: 0.50 0.01 0.01 0.01 0.01 0.00 0.00 0.00\n' $line_num
line_num=$((line_num+1))
printf '%4d: 0.01 0.01 0.01 0.47 0.00 0.00 0.00 0.00\n' $line_num
line_num=$((line_num+1))
{
printf '%4d: 0.50 0.00 0.00 0.00 0.00 0.00 0.00 0.00\n' $line_num
line_num=$((line_num+1))
printf '%4d: 0.50 0.01 0.00 0.00 0.00 0.00 0.00 0.00\n' $line_num
line_num=$((line_num+1))
printf '%4d: 0.50 0.01 0.01 0.00 0.00 0.00 0.00 0.00\n' $line_num
line_num=$((line_num+1))
printf '%4d: 0.50 0.01 0.01 0.01 0.00 0.00 0.00 0.00\n' $line_num
line_num=$((line_num+1))
printf '%4d: 0.50 0.01 0.01 0.01 0.01 0.00 0.00 0.00\n' $line_num
line_num=$((line_num+1))
printf '%4d: 0.50 0.01 0.01 0.01 0.01 0.01 0.00 0.00\n' $line_num
line_num=$((line_num+1))
printf '%4d: 0.50 0.01 0.01 0.01 0.01 0.01 0.01 0.00\n' $line_num
line_num=$((line_num+1))
printf '%4d: 0.50 0.01 0.01 0.01 0.01 0.01 0.01 0.01\n' $line_num
line_num=$((line_num+1))
}
{
printf '%4d: 1.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00\n' $line_num
line_num=$((line_num+1))
printf '%4d: 0.99 0.01 0.00 0.00 0.00 0.00 0.00 0.00\n' $line_num
line_num=$((line_num+1))
printf '%4d: 0.98 0.01 0.01 0.00 0.00 0.00 0.00 0.00\n' $line_num
line_num=$((line_num+1))
printf '%4d: 0.97 0.01 0.01 0.01 0.00 0.00 0.00 0.00\n' $line_num
line_num=$((line_num+1))
printf '%4d: 0.96 0.01 0.01 0.01 0.01 0.00 0.00 0.00\n' $line_num
line_num=$((line_num+1))
printf '%4d: 0.95 0.01 0.01 0.01 0.01 0.01 0.00 0.00\n' $line_num
line_num=$((line_num+1))
printf '%4d: 0.94 0.01 0.01 0.01 0.01 0.01 0.01 0.00\n' $line_num
line_num=$((line_num+1))
printf '%4d: 0.93 0.01 0.01 0.01 0.01 0.01 0.01 0.01\n' $line_num
line_num=$((line_num+1))
}
{
for (( i=7 ; i<=50 ; i++ )) do
printf '%4d: 0.07 0.07 0.07 0.07 0.07 0.07 0.07 0.%02d\n' $line_num $i
line_num=$((line_num+1))
done
}
printf '%4d: 0.19 0.19 0.06 0.03 0.02 0.01 0.00 0.00\n' $line_num
line_num=$((line_num+1))
printf '%4d: 0.19 0.19 0.19 0.19 0.19 0.05 0.00 0.00\n' $line_num
line_num=$((line_num+1))
printf '%4d: 0.01 0.01 0.01 0.01 0.11 0.11 0.32 0.32\n' $line_num
line_num=$((line_num+1))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment