svn commit: r322252 - head/usr.bin/vmstat
Emmanuel Vadot
manu at bidouilliste.com
Wed Aug 9 09:40:52 UTC 2017
On Wed, 9 Aug 2017 18:44:19 +1000 (EST)
Bruce Evans <brde at optusnet.com.au> wrote:
> On Tue, 8 Aug 2017, Emmanuel Vadot wrote:
>
> > On Tue, 8 Aug 2017 23:55:52 +1000 (EST)
> > Bruce Evans <brde at optusnet.com.au> wrote:
> >
> >> On Tue, 8 Aug 2017, Emmanuel Vadot wrote:
> >>
> >>> Log:
> >>> vmstat: Always emit a space after the free-memory column
> >>>
> >>> When displaying in non-human form, if the free-memory number
> >>> is large (more than 7 digits), there is no space between it and
> >>> the page fault column.
> >>>
> >>> PR: 221290
> >>> Submitted by: Josuah Demangeon <mail at josuah.net> (Original version)
> >>>
> >>> Modified:
> >>> head/usr.bin/vmstat/vmstat.c
> >>>
> >>> Modified: head/usr.bin/vmstat/vmstat.c
> >>> ==============================================================================
> >>> --- head/usr.bin/vmstat/vmstat.c Tue Aug 8 11:49:36 2017 (r322251)
> >>> +++ head/usr.bin/vmstat/vmstat.c Tue Aug 8 12:18:11 2017 (r322252)
> >>> @@ -832,6 +832,7 @@ dovmstat(unsigned int interval, int reps)
> >>> xo_emit(" ");
> >>> xo_emit("{:free-memory/%7d}",
> >>> vmstat_pgtok(total.t_free));
> >>> + xo_emit(" ");
> >>> }
> >>> xo_emit("{:total-page-faults/%5lu} ",
> >>> (unsigned long)rate(sum.v_vm_faults -
> >>
> >> This seems to break the formatting. There was a negative amount of space
> >> available for expansion, and since the header was not expanded to match
> >> its alignment with the fields is more random than before. With -h, the
> >> width was 80 columns, giving ugly line wrap on 80-column terminals with
> >> auto-wrap. Now it is 81 columns, giving uglier line wrap on all 80-
> >> column terminals.
> >
> > This break nothing, This was the case before too (with or without
> > -h), just tested in tmux with force-width 80.
>
> Testing shows that it breaks the -H case as expected. (I had misread the
> change as affecting the -h case too.)
>
> Before:
>
> X procs memory page disks faults cpu
> X r b w avm fre flt re pi po fr sr ad0 ad1 in sy cs us sy id
> X 0 0 0 12719376 977460 2167 3 28 0 2545 451 0 0 268 27162 7175 9 1 91
>
> Misformatting in the data line starts with the avm field taking 8 of the 7
> columns reserved for it. This and all subsequent fields are misaligned with
> the header.
>
> The header is pre-misformatted to width 85, with lots of inconsistencies in
> the first line. Old versions were carefully formatted to width 79, with no
> inconsistencies in the first line. The extra width for avm makes the extra
> width for the header not even work to line up.
>
> X procs memory page disks faults cpu
> X r b w avm fre flt re pi po fr sr ad0 ad1 in sy cs us sy id
> X 0 0 0 12719380 977460 2167 3 28 0 2545 451 0 0 268 27162 7175 9 1 91
>
> The new bugs are that the extra space before the "flt" field increases the
> off-by-1 error to off-by-2 for this field and all subsequent fields. All
> fields starting with "flt" now have an error of at least off-by-1 even
> if none are too wide, since the header was not expanded to match. Expansion
> would increase its breakage from 6 to wide to 7 too wide.
Thanks, I know see the problem.
I'll see if this could be corrected easily with libxo ...
> >> The bugs were mostly in the first line of the header:
> >> - the second line of the header was correct for vmstat -h
> >> - for vmstat without -h, the second line of the header was apparently broken
> >> by a change like the one here, that added a space after the "r b w" fields
> >> without adding one in the "r b w" header
> >> - most of the fields in the first line of the header are misaligned with the
> >> second lone. Many have drifted 3 to the left of where the were in a sort
> >> of center-justified place. Some of these might have actually been
> >> intended to be left justified, but had an off by +1 error. Now these
> >> have an error of off by -2 relative to left justifications.
> >>
> >> Only the "memory" header in the first line is better than in old versions.
> >> It is now left justified. Left justifying all headers in the first line
> >> is probably best. I couldn't find a good way to delimit the right hand
> >> side of the extents of the headers in the first line. The second line of
> >> the headers already uses right justification consistently and this works
> >> well.
> >
> > I think that all this might be true but you might talk about the whole
> > libxo conversion that was done, not my commit right ?
>
> I try not to look at libxo, since its misformattings are enormous starting
> in the source code.
>
> My columnize.awk script works almost perfectly to fix the above
> misformattings:
>
> X BEGIN {
> X columns = 79 # XXX
> X }
> X
> X {
> X # Determine fields and field widths for current line.
> X # awk's field splitting feature turned out to be inadequate,
> X # and this would be even easier in C.
> X n = split($0, a, "")
> X f = 1
> X j = 1
> X while (j <= n) {
> X cpw[f] = 0
> X cfw[f] = 0
> X while (j <= n && a[j] == " ") {
> X cpw[f]++ # current (left) padding width
> X j++
> X }
> X if (j > n)
> X break
> X while (j <= n && a[j] != " ") {
> X cfw[f]++ # current field width without padding
> X j++
> X }
> X fld[f] = substr($0, j - cfw[f], cfw[f])
> X if (f != 1) {
> X cpw[f]--
> X cfw[f]++ # current field width with min padding
> X }
> X f++
> X }
> X nf = f - 1 # no need to use or trust NF
> X
> X if (NR == 1 || NR < 3 && nf != anf) {
> X # Make current field widths (with full padding) the maximum
> X # ones. When NR > 1, this discards the previous maximums.
> X # Good enough for vmstat, where the widths from NR == 1 are
> X # garbage.
> X #
> X # Make current field widths (with minimal padding) the minimum
> X # ones.
> X anf = nf
> X for (f = 1; f <= anf; f++) {
> X Mfw[f] = cpw[f] + cfw[f]
> X mfw[f] = cfw[f]
> X }
> X } else if (nf < anf) {
> X # Some non-tabular line after warming up. Probably an ornate
> X # line in the next header. Too hard to handle properly.
> X printf("%.*s oops\n", columns - 5, $0)
> X fflush(stdout)
> X next
> X } else if (nf > anf) {
> X # Some non-tabular line after warming up. Hopefully just
> X # a single trailing field with inadequate field separators
> X # like the COMMAND field in ps and top. Append the extras
> X # to the last field with minimal separators.
> X for (f = anf + 1; f <= nf; f++)
> X fld[anf] = fld[anf] " " fld[f]
> X nf = anf
> X cfw[nf] = 1 + length(fld[nf])
> X }
> X
> X # Update the maximum and minimum field widths if this line needs
> X # wider fields.
> X len = 0
> X for (f = 1; f <= nf; f++) {
> X if (Mfw[f] < cfw[f])
> X Mfw[f] = cfw[f]
> X len += Mfw[f]
> X if (mfw[f] < cfw[f])
> X mfw[f] = cfw[f]
> X }
> X
> X # If the line would be too wide, reduce the maximum field widths
> X # minimally towards minimum ones.
> X while (len > columns) {
> X for (f = 1; f <= nf; f++) {
> X if (Mfw[f] > mfw[f]) {
> X Mfw[f]--
> X len--
> X break
> X }
> X }
> X if (f > nf)
> X break
> X }
> X
> X s = ""
> X for (f = 1; f <= nf - 1; f++)
> X s = s sprintf("%*s", Mfw[f], fld[f])
> X s = s sprintf(" %-*s", Mfw[nf] - 1, fld[nf])
> X printf("%.*s\n", columns, s)
> X fflush(stdout)
> X }
>
> When applied to the above saved output (old then new, quoted by X's), it
> produces:
>
> X procs memory page disks faults cpu
> X r b w avm fre flt re pi po fr sr ad0 ad1 in sy cs us sy id
> X 0 0 0 12719376 977460 2167 3 28 0 2545 451 0 0 268 27162 7175 9 1 91
> X procs memory page disks faults oops
> X r b w avm fre flt re pi po fr sr ad0 ad1 in sy cs us sy id
> X 0 0 0 12719380 977460 2167 3 28 0 2545 451 0 0 268 27162 7175 9 1 91
>
> It removed enough spaces to fit in 79 columns even with the X's. It can't
> handle the first line of the header very well since this line has an ornate
> format whose columns don't match the rest of the output in any simple way
> (programs should produce more parseable formats, like ps does). All that
> that it did for the first line was move "cpu" to a less worse place in the
> old output and change it to "oops" in the new output.
>
> Even programs like ps and df that attempt to do the necessary dynamic
> formatting often produce worse results than the above script. df on
> freefall now produces a mess lots of spaces giving long lines even with
> -h, I think because the mountpoint names are very long and df has hard-
> coded formats for everything else. columnize.awk only manages to almost
> clean this up for the -h case. It has a problem that it is stream-based
> and doesn't backtrack to adjust early lines. This is necessary for use
> in filters.
>
> vmstat 1 | awk -f columize.awk is a good example of using columize.awk
> in a filter. This use also requires it to understand headers not in
> the first few lines of output. This is not easy, and in practice it
> gets confused by the first line of the vmstat header unless it is the
> first line of the output. This is why it printed "oops" in the
> abov concatenated output. The first header line just has an unusual
> number of fields so cannot be handled right. When it is the first
> line in the output, it is printed verbatim except possibly for removing
> spaces, since it gives the only available information on the expected
> columnar output.
>
> Bruce
--
Emmanuel Vadot <manu at bidouilliste.com> <manu at freebsd.org>
More information about the svn-src-head
mailing list