2 * Copyright (c) 1990, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 static char sccsid
[] = "@(#)print.c 8.6 (Berkeley) 4/16/94";
38 static const char rcsid
[] =
39 "$FreeBSD: print.c,v 1.33 1998/11/25 09:34:00 dfr Exp $";
42 #include <sys/param.h>
44 #include <sys/resource.h>
45 #include <sys/ucred.h>
49 #include <sys/ucred.h>
51 #include <sys/sysctl.h>
52 #include <sys/cdefs.h>
72 extern int mflg
, print_all_thread
, print_thread_num
;
80 STAILQ_FOREACH(vent
, &varlist
, next_ve
)
81 if (*vent
->header
!= '\0')
86 STAILQ_FOREACH(vent
, &varlist
, next_ve
) {
88 if (v
->flag
& LJUST
) {
89 if (STAILQ_NEXT(vent
, next_ve
) == NULL
) /* last one */
90 (void)printf("%s", vent
->header
);
92 (void)printf("%-*s", v
->width
, vent
->header
);
94 (void)printf("%*s", v
->width
, vent
->header
);
95 if (STAILQ_NEXT(vent
, next_ve
) != NULL
)
102 * Get command and arguments.
104 * If the global variable eflg is non-zero and the user has permission to view
105 * the process's environment, the environment is included.
107 * on return argvlen is the length of the extracted string, argv0len is
108 * the length of the command (same as argvlen if show_args is true)
111 getproclline(KINFO
*k
, char **command_name
, int *argvlen
, int *argv0len
,
114 int mib
[3], argmax
, nargs
, c
= 0;
116 char *procargs
, *sp
, *np
, *cp
;
119 /* Get the maximum process arguments size. */
121 mib
[1] = KERN_ARGMAX
;
123 size
= sizeof(argmax
);
124 if (sysctl(mib
, 2, &argmax
, &size
, NULL
, 0) == -1) {
128 /* Allocate space for the arguments. */
129 procargs
= (char *)malloc(argmax
);
130 if (procargs
== NULL
) {
135 * Make a sysctl() call to get the raw argument space of the process.
136 * The layout is documented in start.s, which is part of the Csu
137 * project. In summary, it looks like:
139 * /---------------\ 0x00000000
162 * |---------------| <-- Beginning of data returned by sysctl() is here.
170 * |---------------| <-- Top of stack.
173 * \---------------/ 0xffffffff
176 mib
[1] = KERN_PROCARGS2
;
177 mib
[2] = KI_PROC(k
)->p_pid
;
179 size
= (size_t)argmax
;
180 if (sysctl(mib
, 3, procargs
, &size
, NULL
, 0) == -1) {
184 memcpy(&nargs
, procargs
, sizeof(nargs
));
185 cp
= procargs
+ sizeof(nargs
);
187 /* Skip the saved exec_path. */
188 for (; cp
< &procargs
[size
]; cp
++) {
190 /* End of exec_path reached. */
194 if (cp
== &procargs
[size
]) {
198 /* Skip trailing '\0' characters. */
199 for (; cp
< &procargs
[size
]; cp
++) {
201 /* Beginning of first argument reached. */
205 if (cp
== &procargs
[size
]) {
208 /* Save where the argv[0] string starts. */
212 * Iterate through the '\0'-terminated strings and convert '\0' to ' '
213 * until a string is found that has a '=' character in it (or there are
214 * no more strings in procargs). There is no way to deterministically
215 * know where the command arguments end and the environment strings
216 * start, which is why the '=' character is searched for as a heuristic.
218 for (np
= NULL
; c
< nargs
&& cp
< &procargs
[size
]; cp
++) {
222 /* Convert previous '\0'. */
227 /* Note location of current '\0'. */
232 * Don't convert '\0' characters to ' '.
233 * However, we needed to know that the
234 * command name was terminated, which we
243 * If eflg is non-zero, continue converting '\0' characters to ' '
244 * characters until no more strings that look like environment settings
247 if ( show_args
&& (eflg
!= 0) && ( (getuid() == 0) || (KI_EPROC(k
)->e_pcred
.p_ruid
== getuid()) ) ) {
248 for (; cp
< &procargs
[size
]; cp
++) {
253 * Two '\0' characters in a row.
254 * This should normally only
255 * happen after all the strings
256 * have been seen, but in any
257 * case, stop parsing.
261 /* Convert previous '\0'. */
264 /* Note location of current '\0'. */
271 * sp points to the beginning of the arguments/environment string, and
272 * np should point to the '\0' terminator for the string.
274 if (np
== NULL
|| np
== sp
) {
275 /* Empty or unterminated string. */
279 /* Make a copy of the string. */
280 *argvlen
= asprintf(command_name
, "%s", sp
);
290 = asprintf(command_name
, "(%s)", KI_PROC(k
)->p_comm
);
293 /* Return value is malloc'ed, please free it */
295 get_command_and_or_args(KINFO
*k
, int show_cmd
, int show_args
)
300 int cmdlen
, argv0len
= 0;
303 if(!mflg
|| (print_all_thread
&& (print_thread_num
== 0))) {
304 getproclline(k
, &rawcmd
, &cmdlen
, &argv0len
, show_args
);
307 /* Ignore the path in cmd, if any. */
308 for (cmd
= &rawcmd
[cmdlen
- 1]; cmd
> rawcmd
; cmd
--) {
325 if ((vis_args
= malloc(strlen(cmd
) * 4 + 1)) == NULL
)
327 strvis(vis_args
, cmd
, VIS_TAB
| VIS_NL
| VIS_NOSLASH
);
336 s_command_and_or_args(KINFO
*k
, int show_cmd
, int show_args
)
338 char *s
= get_command_and_or_args(k
, show_cmd
, show_args
);
346 p_command_and_or_args(KINFO
*k
, VARENT
*ve
, int show_cmd
, int show_args
,
350 char *s
= get_command_and_or_args(k
, show_cmd
, show_args
);
352 if (STAILQ_NEXT(ve
, next_ve
) == NULL
) {
354 if (termwidth
== UNLIMITED
) {
360 left
= termwidth
- (totwidth
- v
->width
);
361 if (left
< 1 || no_trunc
) {
362 /* already wrapped, just use std * width */
365 for(cp
= s
; --left
>= 0 && *cp
;) {
366 (void)putchar(*cp
++);
371 (void)printf("%-*.*s", v
->width
, v
->width
, s
);
377 int s_command(KINFO
*k
) {
378 return s_command_and_or_args(k
, 1, !cflag
);
381 int s_args(KINFO
*k
) {
382 return s_command_and_or_args(k
, 1, 1);
385 int s_just_command(KINFO
*k
) {
386 return s_command_and_or_args(k
, 1, 0);
389 void command(KINFO
*k
, VARENT
*ve
) {
390 p_command_and_or_args(k
, ve
, 1, !cflag
, 0);
393 void args(KINFO
*k
, VARENT
*ve
) {
394 p_command_and_or_args(k
, ve
, 1, 1, 1);
397 void just_command(KINFO
*k
, VARENT
*ve
) {
398 p_command_and_or_args(k
, ve
, 1, 0, 0);
409 (void)printf("%-*s", v
->width
, KI_PROC(k
)->p_comm
);
415 register struct passwd
*pw
;
416 struct passwd
*getpwuid();
418 pw
= getpwuid((short)uid
);
422 return( pw
->pw_name
);
426 logname(KINFO
*k
, VARENT
*ve
)
432 (void)printf("%-*s", v
->width
, (s
= getname(KI_EPROC(k
)->e_ucred
.cr_uid
), *s
) ? s
: "-");
435 extern int mach_state_order();
441 struct extern_proc
*p
;
446 extern char mach_state_table
[];
465 *cp
= mach_state_table
[k
->state
];
470 else if (p
->p_nice
> 0)
474 if (flag
& P_WEXIT
&& p
->p_stat
!= SZOMB
)
478 if (flag
& (P_SYSTEM
| P_NOSWAP
| P_PHYSIO
))
480 if (KI_EPROC(k
)->e_flag
& EPROC_SLEADER
)
482 if ((flag
& P_CONTROLT
) && KI_EPROC(k
)->e_pgid
== KI_EPROC(k
)->e_tpgid
)
485 (void)printf("%-*s", v
->width
, buf
);
486 } else if (print_all_thread
) {
487 j
= mach_state_order(k
->thval
[print_thread_num
].tb
.run_state
,
488 k
->thval
[print_thread_num
].tb
.sleep_time
);
489 *cp
++ = mach_state_table
[j
];
491 (void)printf("%-*s", v
->width
, buf
);
493 (void)printf("%-*s", v
->width
, " ");
509 (void)printf("%*d", v
->width
, k
->curpri
);
510 } else if (print_all_thread
) {
511 switch(k
->thval
[print_thread_num
].tb
.policy
) {
512 case POLICY_TIMESHARE
:
513 j
= k
->thval
[print_thread_num
].schedinfo
.tshare
.cur_priority
;
517 j
= k
->thval
[print_thread_num
].schedinfo
.fifo
.base_priority
;
521 j
= k
->thval
[print_thread_num
].schedinfo
.rr
.base_priority
;
527 (void)printf("%*d%c", v
->width
- 1, j
, c
);
530 (void)printf("%*d", v
->width
, j
);
543 if(!mflg
|| (print_all_thread
&& (print_thread_num
== 0)))
546 user_from_uid(KI_EPROC(k
)->e_ucred
.cr_uid
, 0));
548 (void)printf("%-*s", (int)v
->width
, " ");
554 return (strlen(user_from_uid(KI_EPROC(k
)->e_ucred
.cr_uid
, 0)));
566 (int)v
->width
, user_from_uid(KI_EPROC(k
)->e_pcred
.p_ruid
, 0));
572 return (strlen(user_from_uid(KI_EPROC(k
)->e_pcred
.p_ruid
, 0)));
585 dev
= KI_EPROC(k
)->e_tdev
;
587 (void)printf("%*s", v
->width
, "??");
589 (void)snprintf(buff
, sizeof(buff
),
590 "%d/%d", major(dev
), minor(dev
));
591 (void)printf("%*s", v
->width
, buff
);
606 if(!mflg
|| (print_all_thread
&& (print_thread_num
== 0))) {
607 dev
= KI_EPROC(k
)->e_tdev
;
608 if (dev
== NODEV
|| (ttname
= devname(dev
, S_IFCHR
)) == NULL
)
609 (void)printf("%*s ", v
->width
-1, "??");
611 if (strncmp(ttname
, "tty", 3) == 0 ||
612 strncmp(ttname
, "cua", 3) == 0)
614 (void)printf("%*.*s%c", v
->width
-1, v
->width
-1, ttname
,
615 KI_EPROC(k
)->e_flag
& EPROC_CTTY
? ' ' : '-');
619 (void)printf("%*s ", v
->width
-1, " ");
633 dev
= KI_EPROC(k
)->e_tdev
;
634 if (dev
== NODEV
|| (ttname
= devname(dev
, S_IFCHR
)) == NULL
)
635 (void)printf("%-*s", v
->width
, "??");
637 (void)printf("%-*s", v
->width
, ttname
);
641 started(KINFO
*k
, VARENT
*ve
)
646 static int use_ampm
= -1;
651 use_ampm
= (*nl_langinfo(T_FMT_AMPM
) != '\0');
652 then
= KI_PROC(k
)->p_starttime
.tv_sec
;
653 tp
= localtime(&then
);
654 if (now
- KI_PROC(k
)->p_starttime
.tv_sec
< 24 * 3600) {
655 (void)strftime(buf
, sizeof(buf
),
656 use_ampm
? "%l:%M%p" : "%k:%M ", tp
);
657 } else if (now
- KI_PROC(k
)->p_starttime
.tv_sec
< 7 * 86400) {
658 (void)strftime(buf
, sizeof(buf
),
659 use_ampm
? "%a%I%p" : "%a%H ", tp
);
661 (void)strftime(buf
, sizeof(buf
), "%e%b%y", tp
);
662 (void)printf("%-*s", v
->width
, buf
);
675 then
= KI_PROC(k
)->p_starttime
.tv_sec
;
676 (void)strftime(buf
, sizeof(buf
) -1, "%c", localtime(&then
));
677 (void)printf("%-*s", v
->width
, buf
);
680 char *get_etime(KINFO
*k
) {
682 gettimeofday(&tv
, NULL
);
683 long e
= tv
.tv_sec
- KI_PROC(k
)->p_starttime
.tv_sec
;
687 if (e
> 100*60*60*24) {
688 asprintf(&ret
, "%ld-%02ld:%02ld:%02ld",
693 } else if (e
> 60*60*24) {
694 asprintf(&ret
, "%02ld-%02ld:%02ld:%02ld",
699 } else if (e
> 60*60) {
700 asprintf(&ret
, "%02ld:%02ld:%02ld",
705 asprintf(&ret
, "%02ld:%02ld",
713 void p_etime(KINFO
*k
, VARENT
*ve
) {
714 char *str
= get_etime(k
);
715 printf("%*s", ve
->var
->width
, str
);
719 int s_etime(KINFO
*k
) {
720 char *str
= get_etime(k
);
721 int sz
= strlen(str
);
734 if (KI_PROC(k
)->p_wchan
) {
735 if (KI_PROC(k
)->p_wmesg
)
736 (void)printf("%-*.*s", v
->width
, v
->width
,
737 KI_EPROC(k
)->e_wmesg
);
740 (void)printf("%-*lx", v
->width
,
741 (long)KI_PROC(k
)->p_wchan
&~ KERNBASE
);
743 (void)printf("%-*lx", v
->width
,
744 (long)KI_PROC(k
)->p_wchan
);
747 (void)printf("%-*s", v
->width
, "-");
750 #define pgtok(a) (((a)*getpagesize())/1024)
761 (void)printf("%*d", v
->width
,
762 (KI_EPROC(k
)->e_vm
.vm_map
.size
/1024));
764 (void)printf("%*lu", v
->width
,
765 (u_long
)((k
)->tasks_info
.virtual_size
)/1024);
770 p_rssize(k
, ve
) /* doesn't account for text */
777 /* (void)printf("%*ld", v->width, "-"); */
778 (void)printf("%*lu", v
->width
,
779 (u_long
)((k
)->tasks_info
.resident_size
)/1024);
789 long psecs
; /* "parts" of a second. first micro, then centi */
791 time_value_t total_time
, system_time
;
794 if (KI_PROC(k
)->p_stat
== SZOMB
|| !k
->ki_u
.u_valid
) {
799 * This counts time spent handling interrupts. We could
800 * fix this, but it is not 100% trivial (and interrupt
801 * time fractions only work on the sparc anyway). XXX
804 secs
= KI_PROC(k
)->p_runtime
/ 1000000;
805 psecs
= KI_PROC(k
)->p_runtime
% 1000000;
808 secs
+= k
->ki_u
.u_cru
.ru_utime
.tv_sec
+
809 k
->ki_u
.u_cru
.ru_stime
.tv_sec
;
810 psecs
+= k
->ki_u
.u_cru
.ru_utime
.tv_usec
+
811 k
->ki_u
.u_cru
.ru_stime
.tv_usec
;
814 * round and scale to 100's
816 psecs
= (psecs
+ 5000) / 10000;
821 total_time
= k
->tasks_info
.user_time
;
822 system_time
= k
->tasks_info
.system_time
;
824 time_value_add(&total_time
, &k
->times
.user_time
);
825 time_value_add(&system_time
, &k
->times
.system_time
);
826 time_value_add(&total_time
, &system_time
);
828 secs
= total_time
.seconds
;
829 psecs
= total_time
.microseconds
;
831 * round and scale to 100's
833 psecs
= (psecs
+ 5000) / 10000;
837 (void)snprintf(obuff
, sizeof(obuff
),
838 "%3ld:%02ld.%02ld", secs
/60, secs%60
, psecs
);
839 (void)printf("%*s", v
->width
, obuff
);
849 long psecs
; /* "parts" of a second. first micro, then centi */
851 time_value_t user_time
;
856 user_time
= k
->tasks_info
.user_time
;
857 time_value_add(&user_time
, &k
->times
.user_time
);
858 } else if (print_all_thread
) {
859 user_time
= k
->thval
[print_thread_num
].tb
.user_time
;
861 user_time
.seconds
=0;
862 user_time
.microseconds
=0;
865 secs
= user_time
.seconds
;
866 psecs
= user_time
.microseconds
;
868 * round and scale to 100's
870 psecs
= (psecs
+ 5000) / 10000;
874 (void)snprintf(obuff
, sizeof(obuff
),
875 "%3ld:%02ld.%02ld", secs
/60, secs%60
, psecs
);
876 (void)printf("%*s", v
->width
, obuff
);
886 long psecs
; /* "parts" of a second. first micro, then centi */
888 time_value_t system_time
;
892 system_time
= k
->tasks_info
.system_time
;
893 time_value_add(&system_time
, &k
->times
.system_time
);
894 } else if (print_all_thread
) {
895 system_time
= k
->thval
[print_thread_num
].tb
.system_time
;
897 system_time
.seconds
=0;
898 system_time
.microseconds
=0;
900 secs
= system_time
.seconds
;
901 psecs
= system_time
.microseconds
;
903 * round and scale to 100's
905 psecs
= (psecs
+ 5000) / 10000;
909 (void)snprintf(obuff
, sizeof(obuff
),
910 "%3ld:%02ld.%02ld", secs
/60, secs%60
, psecs
);
911 (void)printf("%*s", v
->width
, obuff
);
928 #define fxtofl(fixpt) ((double)(fixpt) / fscale)
930 /* XXX - I don't like this */
931 if (p
->p_swtime
== 0 || (p
->p_flag
& P_INMEM
) == 0)
934 return (100.0 * fxtofl(p
->p_pctcpu
));
935 return (100.0 * fxtofl(p
->p_pctcpu
) /
936 (1.0 - exp(p
->p_swtime
* log(fxtofl(ccpu
)))));
938 return (k
->cpu_usage
);
942 #ifndef TH_USAGE_SCALE
943 #define TH_USAGE_SCALE 1000
944 #endif /* !TH_USAGE_SCALE */
947 pcpu(KINFO
*k
, VARENT
*ve
)
954 } else if (print_all_thread
) {
955 cp
= k
->thval
[print_thread_num
].tb
.cpu_usage
;
961 (void)printf("%*.1f", v
->width
, ((double)cp
) * 100.0 / ((double)TH_USAGE_SCALE
));
978 if ((p
->p_flag
& P_INMEM
) == 0)
980 /* XXX want pmap ptpages, segtab, etc. (per architecture) */
982 /* XXX don't have info about shared */
983 fracmem
= ((float)e
->e_vm
.vm_rssize
+ szptudot
)/mempages
;
984 return (100.0 * fracmem
);
986 fracmem
= ((float)k
->tasks_info
.resident_size
)/(double)mempages
;
987 return (100.0 * fracmem
);
999 (void)printf("%*.1f", v
->width
, getpmem(k
));
1010 (void)printf("%*ld", v
->width
,
1011 k
->ki_u
.u_valid
? k
->ki_u
.u_ru
.ru_majflt
: 0);
1023 (void)printf("%*s", v
->width
, "-");
1036 (void)printf("%*ld", v
->width
, (long)pgtok(KI_EPROC(k
)->e_vm
.vm_tsize
));
1038 (void)printf("%*ld", v
->width
, (long)dummy
);
1050 struct rtprio
*prtp
;
1052 unsigned prio
, type
;
1055 prtp
= (struct rtprio
*) ((char *)KI_PROC(k
) + v
->off
);
1059 case RTP_PRIO_REALTIME
:
1060 snprintf(str
, sizeof(str
), "real:%u", prio
);
1062 case RTP_PRIO_NORMAL
:
1063 strncpy(str
, "normal", sizeof(str
));
1066 snprintf(str
, sizeof(str
), "idle:%u", prio
);
1069 snprintf(str
, sizeof(str
), "%u:%u", type
, prio
);
1072 str
[sizeof(str
) - 1] = '\0';
1073 (void)printf("%*s", v
->width
, str
);
1078 * Generic output routines. Print fields from various prototype
1082 printval(void *bp
, VAR
*v
)
1084 static char ofmt
[32] = "%";
1090 if (v
->flag
& LJUST
)
1093 while ((*cp
++ = *fcp
++));
1097 (void)printf(ofmt
, v
->width
, *(char *)bp
);
1100 (void)printf(ofmt
, v
->width
, *(u_char
*)bp
);
1103 (void)printf(ofmt
, v
->width
, *(short *)bp
);
1106 (void)printf(ofmt
, v
->width
, *(u_short
*)bp
);
1109 (void)printf(ofmt
, v
->width
, *(int *)bp
);
1112 (void)printf(ofmt
, v
->width
, *(u_int
*)bp
);
1115 (void)printf(ofmt
, v
->width
, *(long *)bp
);
1118 (void)printf(ofmt
, v
->width
, *(u_long
*)bp
);
1122 (void)printf(ofmt
, v
->width
, *(u_long
*)bp
&~ KERNBASE
);
1124 (void)printf(ofmt
, v
->width
, *(u_long
*)bp
);
1128 errx(1, "unknown type %d", v
->type
);
1140 printval((char *)((char *)KI_PROC(k
) + v
->off
), v
);
1151 printval((char *)((char *)KI_EPROC(k
) + v
->off
), v
);
1162 if (k
->ki_u
.u_valid
)
1163 printval((char *)((char *)&k
->ki_u
+ v
->off
), v
);
1165 (void)printf("%*s", v
->width
, "-");
1176 if (k
->ki_u
.u_valid
)
1177 printval((char *)((char *)(&k
->ki_u
.u_ru
) + v
->off
), v
);
1179 (void)printf("%*s", v
->width
, "-");
1183 wq(KINFO
*k
, VARENT
*ve
)
1186 struct proc_workqueueinfo wqinfo
;
1191 len
= sizeof(wqinfo
);
1192 ret
= proc_pidinfo(KI_PROC(k
)->p_pid
, PROC_PIDWORKQUEUEINFO
, 0, &wqinfo
, len
);
1196 if (len
== ret
&& len
== PROC_PIDWORKQUEUEINFO_SIZE
) {
1197 if (strcmp(v
->name
, "wql") == 0) {
1199 switch (wqinfo
.pwq_state
& (WQ_EXCEEDED_CONSTRAINED_THREAD_LIMIT
| WQ_EXCEEDED_TOTAL_THREAD_LIMIT
)) {
1203 case WQ_EXCEEDED_CONSTRAINED_THREAD_LIMIT
:
1206 case WQ_EXCEEDED_TOTAL_THREAD_LIMIT
:
1213 printf("%*s", v
->width
, s
);
1216 if (strcmp(v
->name
, "wqr") == 0)
1217 nthreads
= wqinfo
.pwq_runthreads
;
1218 else if (strcmp(v
->name
, "wqb") == 0)
1219 nthreads
= wqinfo
.pwq_blockedthreads
;
1221 nthreads
= wqinfo
.pwq_nthreads
;
1222 printf("%*d", v
->width
, nthreads
);
1224 printf("%*s", v
->width
, "-");