Add netbw option to systat
Bryan Venteicher
bryanv at daemoninthecloset.org
Fri Jul 11 05:36:53 UTC 2014
On Thu, Jul 10, 2014 at 11:50 PM, Bruce Evans <brde at optusnet.com.au> wrote:
> On Thu, 10 Jul 2014, John Baldwin wrote:
>
> On Wednesday, July 02, 2014 8:54:41 pm hiren panchasara wrote:
>>
>>> On Wed, Jul 2, 2014 at 4:50 PM, Bryan Venteicher
>>> <bryanv at daemoninthecloset.org> wrote:
>>>
>>>> I'd like to commit this if anybody else thinks they'd find it useful.
>>>>
>>>> http://people.freebsd.org/~bryanv/patches/systat-netbw.patch
>>>>
>>> ...
>>
>> 4) Should numtok() just be humanize_number? Or rather, would it simplify
>> the code to use humanize_number? (It might not, but if it does, I
>> think that would be preferable.)
>>
>
> No, nothing should use dehumanize(scientificize)_number(). It is a
> badly designed API that doesn't even support unsigned numbers or
> intmax_t. But numtok() takes a floating point arg. (It is always
> used for rates that really do need floating point or perhaps a
> quotient of integers. Except under #if 0, it is called on intger
> args. It doesn't support this case since it always geenrates a
> %5.Nf format with N > 0 (except for numbers < 0.001 it prints nothing,
> perhaps because %f format doesn't work well for this case).
>
> systat already hads the better functions putint(), putfloat() and
> putlongdouble(). Unfortunately, these are static in vmstat.c. They
> should be used throughout systat to get a consistent format.
> numtok() takes a double arg and could be handled at some cost in
> efficiency by putlongdouble(). (putlongdouble() only exists due
> to design errors in libdevstat. Old parts of systat -v use floats
> and floats are more than adequate, but libdevstat uses long doubles.
> Probably downcasting the long doubles to float would work in
> systat -v, but putfloat() was cloned to create putlongdouble()
> instead.)
>
> putlongdouble() prints the output, but numtok() formats the output for
> printing and returns it in a static buffer with MAXINDEXES = 8
> generations so that this method is not too fragile. In general, direct
> printing is easier to use, but here the output has be printed at a
> certain place in the window. putlongdouble() takes coordinates for
> each call and prints using move(), addch() and addstr(). It has more
> control over padding characters than printf() can provide or
> humanize_number() can dream of, and uses this to padd with '*' in some
> cases (mainly for numbers that cannot be formatted to fit in the desired
> space. Callers must pass some format info, especially the field width,
> in each call. numtok() basically hard-codes a field width of 6 and a
> format of %5.N%c where %c is the suffix. This format wastes 1 character
> for the suffix when the suffix is ' '. putlongdouble() and even
> dehumanize_number() avoid this wastage. This is more critical when the
> field with is < 6. N > 0 and the decimal point also waste a lot of
> space. putlongdouble() has complications to print 100% as 100% and
> not 100.0% (the latter is 2 characters wider, and especially wasteful).
> dehumanize_number() doesn't have any of the complications for the
> decimal point since it doesn't support floating point.
>
> systat -v (vmstat.c) is mostly written in KNF, but the patch has mounds
> of style bugs, e.g.:
>
>
I was trying to keep the diff small with upstream. I'll make a cleanup
sweep and incorporate your comments. Thanks.
+void
> +shownetbw(void)
> +{
> + double delta_time;
> + struct mytcpcb *elm, *telm;
> + int row;
> +
> + delta_time = (double)(tv_curr.tv_sec - tv_last.tv_sec) - 1.0 +
> + (tv_curr.tv_usec + 1000000 - tv_last.tv_usec) / 1e6;
> + if (delta_time < 0.1)
> + return;
> +
> + mvwprintw(wnd, 0, 0,
> + "tcp accepts %s connects %s "
> + " rcv %s snd %s rexmit %s",
> + numtok(DELTARATE(tcps_accepts)),
> + numtok(DELTARATE(tcps_connects) -
> DELTARATE(tcps_accepts)),
> + numtok(DELTARATE(tcps_rcvbyte)),
> + numtok(DELTARATE(tcps_sndbyte)),
> + numtok(DELTARATE(tcps_sndrexmitbyte)));
> + ...
>
> In KNF, the continuation indent is 4. This helps minimize line splitting,
> and lines are not split unnecessarily. Fixing this and other style bugs
> and pessimizations gives:
>
> @ struct mytcpcb *elm, *telm;
> @ double delta_time;
> @ int row;
> @
> @ delta_time = tv_curr.tv_sec - tv_last.tv_sec +
> @ (tv_curr.tv_usec - tv_last.tv_usec) * 1e-6;
> @ if (delta_time < 0.1)
> @ return;
> @ mvwprintw(wnd, 0, 0,
> @ "tcp accepts %s connects %s rcv %s snd %s rexmit %s",
> @ numtok(DELTARATE(tcps_accepts)),
> @ numtok(DELTARATE(tcps_connects) - DELTARATE(tcps_accepts)),
> @ numtok(DELTARATE(tcps_rcvbyte)),
> @ numtok(DELTARATE(tcps_sndbyte)),
> @ numtok(DELTARATE(tcps_rcvbyte)),
> @ numtok(DELTARATE(tcps_sndrexmitbyte)));
> @ ...
>
> This maps fairly easily to putlongdouble(). You would have to pass window
> coordinates to each call. Maintaining these coordinates is fragile in
> a different way than the above. The above is a combination of hard-coded
> formats and field widths. It looks like it has free format except for
> the initial position and the spaces before "rcv", but the fixed format
> returned by numtok() turns the %s's into %.6s's modulo overflow bugs
> in numtok().
>
> +static const char *
> +numtok(double value)
> +{
> + static char buf[MAXINDEXES][32];
> + static int nexti;
> + static const char *suffixes[] = { " ", "K", "M", "G", "T", NULL };
> + int suffix = 0;
> + const char *fmt;
>
> Initialization in declaration. Unsorted declarations.
>
> +
> + while (value >= 1000.0 && suffixes[suffix+1]) {
> + value /= 1000.0;
> + ++suffix;
> + }
>
> Missing spaces around binary operator. The initialization in the
> declaration
> is a good obfuscation.
>
> Fixing some style bugs gives:
>
> @ /* Next line could be compressed to single characters. */
> @ static const char * const suffixes[] = {
> @ " ", "K", "M", "G", "T", NULL };
> @ static char buf[MAXINDEXES][32];
> @ static int nexti;
> @ const char *fmt;
> @ int suffix;
> @
> @ suffix = 0;
> @ while (value >= 1000 && suffixes[suffix + 1] != NULL) {
> @ value /= 1000;
> @ suffix++;
> @ }
>
> + nexti = (nexti + 1) % MAXINDEXES;
> + if (value < 0.001) {
> + fmt = " ";
> + } else if (value < 1.0) {
> + fmt = "%5.3f%s";
> + } else if (value < 10.0) {
> + fmt = "%5.3f%s";
> + } else if (value < 100.0) {
> + fmt = "%5.2f%s";
> + } else {
> + fmt = "%5.1f%s";
> + }
>
> Excessive braces.
>
> + snprintf(buf[nexti], sizeof(buf[nexti]),
> + fmt, value, suffixes[suffix]);
>
> The usual non-KNF indentation. Splitting the line isn't even needed.
> The usual null error handling for snprintf() failure. Errors are
> sort of handled by using a buffer of size 32 instead of 7 so that if
> the value is too large for the format it is not truncated at length 6
> but messes up the format in the output.
>
> + return (buf[nexti]);
> +}
>
> Bruce
>
More information about the freebsd-net
mailing list