On Tue, Nov 27, 2018 at 11:28:31AM -0600, Scott Cheloha wrote:
> On Sat, Nov 24, 2018 at 04:06:34PM +0100, Klemens Nanni wrote:
> > Sometimes I want to see certain programs with least amount of memory,
> > so this diff implements `o -field' to sort in reverse order.
> >
> > The logic is straight forward:
> >
> > 1. merge common code from argument and command loops into new setorder()
> > 2. introduce global state `rev_order' (set in the helper)
> > 3. move identical code to set up process objects from compare_*()
> > functions into SETORDER macro using global boolean
> >
> > compare_*() are used by qsort(3). To sort in reverse, the macro simply
> > swaps the objects used by the ORDERKEY_* macros. That is it inverts the
> > comparison from `p1 > p2' into `p2 > p1' respectively `p1 < p2'.
> >
> > Works fine for all available fields on amd64, no behaviour change for
> > "normal" order.
> >
> > Feedback? Objections?
>
> [...]
After lingering on this I missed a bug in my initial review. See inline.
> > Index: display.c
> > ===================================================================
> > RCS file: /cvs/src/usr.bin/top/display.c,v
> > retrieving revision 1.57
> > diff -u -p -r1.57 display.c
> > --- display.c 17 Nov 2018 23:10:08 -0000 1.57
> > +++ display.c 24 Nov 2018 14:09:38 -0000
> > @@ -817,7 +817,8 @@ show_help(void)
> > "I | i - toggle the display of idle processes\n"
> > "k [-sig] pid - send signal `-sig' to process `pid'\n"
> > "n|# count - show `count' processes\n"
> > - "o field - specify sort order (size, res, cpu, time, pri, pid,
> > command)\n"
> > + "o [-]field - specify sort order (size, res, cpu, time, pri, pid,
> > command)\n"
> > + " (o -field sorts in reverse)\n"
>
> "o" isn't needed, as contextually you're talking about the 'o' shortcut.
> Maybe "-field reverses order" or "'-' prefix reverses sort order"?
>
> > "P pid - highlight process `pid' (P+ switches highlighting
> > off)\n"
> > "p pid - display process by `pid' (p+ selects all
> > processes)\n"
> > "q - quit\n"
> > Index: machine.c
> > ===================================================================
> > RCS file: /cvs/src/usr.bin/top/machine.c,v
> > retrieving revision 1.95
> > diff -u -p -r1.95 machine.c
> > --- machine.c 17 Nov 2018 23:10:08 -0000 1.95
> > +++ machine.c 24 Nov 2018 14:47:32 -0000
> > @@ -602,6 +602,8 @@ static unsigned char sorted_state[] =
> > 1 /* zombie */
> > };
> >
> > +extern int rev_order;
> > +
> > /*
> > * proc_compares - comparison functions for "qsort"
> > */
> > @@ -631,6 +633,17 @@ static unsigned char sorted_state[] =
> > #define ORDERKEY_CMD \
> > if ((result = strcmp(p1->p_comm, p2->p_comm)) == 0)
> >
> > +/* remove one level of indirection and set sort order */
> > +#define SETORDER do { \
> > + if (rev_order) { \
> > + p1 = *(struct kinfo_proc **) pp2; \
> > + p2 = *(struct kinfo_proc **) pp1; \
> > + } else { \
> > + p1 = *(struct kinfo_proc **) pp1; \
> > + p2 = *(struct kinfo_proc **) pp2; \
> > + } \
> > + } while (0)
> > +
> > /* compare_cpu - the comparison function for sorting by cpu percentage */
> > static int
> > compare_cpu(const void *v1, const void *v2)
> > @@ -640,9 +653,7 @@ compare_cpu(const void *v1, const void *
> > struct kinfo_proc *p1, *p2;
> > int result;
> >
> > - /* remove one level of indirection */
> > - p1 = *(struct kinfo_proc **) pp1;
> > - p2 = *(struct kinfo_proc **) pp2;
> > + SETORDER;
> >
> > ORDERKEY_PCTCPU
> > ORDERKEY_CPUTIME
> > @@ -663,9 +674,7 @@ compare_size(const void *v1, const void
> > struct kinfo_proc *p1, *p2;
> > int result;
> >
> > - /* remove one level of indirection */
> > - p1 = *(struct kinfo_proc **) pp1;
> > - p2 = *(struct kinfo_proc **) pp2;
> > + SETORDER;
> >
> > ORDERKEY_MEM
> > ORDERKEY_RSSIZE
> > @@ -686,9 +695,7 @@ compare_res(const void *v1, const void *
> > struct kinfo_proc *p1, *p2;
> > int result;
> >
> > - /* remove one level of indirection */
> > - p1 = *(struct kinfo_proc **) pp1;
> > - p2 = *(struct kinfo_proc **) pp2;
> > + SETORDER;
> >
> > ORDERKEY_RSSIZE
> > ORDERKEY_MEM
> > @@ -709,9 +716,7 @@ compare_time(const void *v1, const void
> > struct kinfo_proc *p1, *p2;
> > int result;
> >
> > - /* remove one level of indirection */
> > - p1 = *(struct kinfo_proc **) pp1;
> > - p2 = *(struct kinfo_proc **) pp2;
> > + SETORDER;
> >
> > ORDERKEY_CPUTIME
> > ORDERKEY_PCTCPU
> > @@ -732,9 +737,7 @@ compare_prio(const void *v1, const void
> > struct kinfo_proc *p1, *p2;
> > int result;
> >
> > - /* remove one level of indirection */
> > - p1 = *(struct kinfo_proc **) pp1;
> > - p2 = *(struct kinfo_proc **) pp2;
> > + SETORDER;
> >
> > ORDERKEY_PRIO
> > ORDERKEY_PCTCPU
> > @@ -754,9 +757,7 @@ compare_pid(const void *v1, const void *
> > struct kinfo_proc *p1, *p2;
> > int result;
> >
> > - /* remove one level of indirection */
> > - p1 = *(struct kinfo_proc **) pp1;
> > - p2 = *(struct kinfo_proc **) pp2;
> > + SETORDER;
> >
> > ORDERKEY_PID
> > ORDERKEY_PCTCPU
> > @@ -777,9 +778,7 @@ compare_cmd(const void *v1, const void *
> > struct kinfo_proc *p1, *p2;
> > int result;
> >
> > - /* remove one level of indirection */
> > - p1 = *(struct kinfo_proc **) pp1;
> > - p2 = *(struct kinfo_proc **) pp2;
> > + SETORDER;
> >
> > ORDERKEY_CMD
> > ORDERKEY_PCTCPU
> > Index: top.1
> > ===================================================================
> > RCS file: /cvs/src/usr.bin/top/top.1,v
> > retrieving revision 1.70
> > diff -u -p -r1.70 top.1
> > --- top.1 2 Nov 2018 12:46:10 -0000 1.70
> > +++ top.1 23 Nov 2018 21:50:39 -0000
> > @@ -35,7 +35,7 @@
> > .Op Fl 1bCHIinqSu
> > .Op Fl d Ar count
> > .Op Fl g Ar string
> > -.Op Fl o Ar field
> > +.Op Fl o Oo - Oc Ns Ar field
> > .Op Fl p Ar pid
> > .Op Fl s Ar time
> > .Op Fl U Oo - Oc Ns Ar user
> > @@ -137,13 +137,16 @@ mode.
> > This is identical to
> > .Em batch
> > mode.
> > -.It Fl o Ar field
> > +.It Fl o Oo - Oc Ns Ar field
> > Sort the process display area using the specified
> > .Ar field
> > as the primary key.
> > The field name is the name of the column as seen in the output,
> > but in lower case.
> > The
> > +.Sq -
> > +prefix reverses the order.
>
> My understanding is that an "order" is the actual progression of
> a sequence, while an "ordering" refers to the underlying function
> or rule that gives rise to a given "order" when applied to a set.
>
> So, I *think* you want
>
> "reverses the ordering for the field"
>
> or something similar, but I'm not positive.
>
> > +The
> > .Ox
> > version of
> > .Nm
> > @@ -327,10 +330,13 @@ This acts similarly to the command
> > Show
> > .Ar count
> > processes.
> > -.It o Ar field
> > +.It o Oo - Oc Ns Ar field
> > Sort the process display area using the specified
> > .Ar field
> > as the primary key.
> > +The
> > +.Sq -
> > +prefix reverses the order.
>
> Same thing here.
>
> "reverses the ordering for the field"
>
> > Values are the same as for the
> > .Fl o
> > flag, as detailed above.
> > Index: top.c
> > ===================================================================
> > RCS file: /cvs/src/usr.bin/top/top.c,v
> > retrieving revision 1.97
> > diff -u -p -r1.97 top.c
> > --- top.c 17 Nov 2018 23:10:08 -0000 1.97
> > +++ top.c 24 Nov 2018 15:04:04 -0000
> > @@ -74,6 +74,7 @@ extern int ncpuonline;
> >
> > extern int (*proc_compares[])(const void *, const void *);
> > int order_index;
> > +int rev_order;
> >
> > int displays = 0; /* indicates unspecified */
> > char do_unames = Yes;
> > @@ -93,6 +94,9 @@ int combine_cpus = 0;
> > char topn_specified = No;
> > #endif
> >
> > +struct system_info system_info;
> > +struct statics statics;
> > +
> > /*
> > * these defines enumerate the "strchr"s of the commands in
> > * command_chars
> > @@ -129,12 +133,20 @@ usage(void)
> > extern char *__progname;
> >
> > fprintf(stderr,
> > - "usage: %s [-1bCHIinqSu] [-d count] [-g string] [-o field] "
> > + "usage: %s [-1bCHIinqSu] [-d count] [-g string] [-o [-]field] "
> > "[-p pid] [-s time]\n\t[-U [-]user] [number]\n",
> > __progname);
> > }
> >
> > static int
> > +getorder(char *field)
> > +{
> > + rev_order = field[0] == '-';
> > +
> > + return string_index(rev_order ? field + 1 : field, statics.order_names);
> > +}
> > +
You need to check that the field has an ordering before potentially
modifying rev_order, otherwise a bogus input will have a side effect.
For example, with the current code the input "o -notafield" reverses
the ordering.
> > +static int
> > filteruser(char buf[])
> > {
> > const char *errstr;
> > @@ -311,9 +323,6 @@ parseargs(int ac, char **av)
> > }
> > }
> >
> > -struct system_info system_info;
> > -struct statics statics;
> > -
> > int
> > main(int argc, char *argv[])
> > {
> > @@ -381,20 +390,9 @@ main(int argc, char *argv[])
> >
> > /* determine sorting order index, if necessary */
> > if (order_name != NULL) {
> > - if ((order_index = string_index(order_name,
> > - statics.order_names)) == -1) {
> > - char **pp, msg[512];
> > -
> > - snprintf(msg, sizeof(msg),
> > - "'%s' is not a recognized sorting order",
> > - order_name);
> > - strlcat(msg, ". Valid are:", sizeof(msg));
> > - pp = statics.order_names;
> > - while (*pp != NULL) {
> > - strlcat(msg, " ", sizeof(msg));
> > - strlcat(msg, *pp++, sizeof(msg));
> > - }
> > - new_message(MT_delayed, msg);
> > + if ((order_index = getorder(order_name)) == -1) {
> > + new_message(MT_delayed,
> > + " %s: unrecognized sorting order", order_name);
>
> And again. Maybe:
>
> "unrecognized sort ordering"
>
> > order_index = 0;
> > }
> > }
> > @@ -879,10 +877,10 @@ rundisplay(void)
> > new_message(MT_standout,
> > "Order to sort: ");
> > if (readline(tempbuf, sizeof(tempbuf)) > 0) {
> > - if ((i = string_index(tempbuf,
> > - statics.order_names)) == -1) {
> > + if ((i = getorder(tempbuf)) == -1) {
> > new_message(MT_standout,
> > " %s: unrecognized sorting order",
> > + tempbuf[0] == '-' ? tempbuf + 1 :
> > tempbuf);
>
> You aren't ducking the '-' during init so I don't think you should hide it
> here.
> You could even refactor the two into something like
>
> void setorder(const char *);
>
> to keep the messages in sync, but that should be done in a subsequent diff.
>
> Also, the "order" vs. "ordering" thing here.
>
> > no_command = Yes;
> > } else
> > ===================================================================
> > Stats: --- 45 lines 1516 chars
> > Stats: +++ 49 lines 1189 chars
> > Stats: 4 lines
> > Stats: -327 chars
> >