4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * The plgrp utility allows a user to display and modify the home lgroup and
31 * lgroup affinities of the specified threads
45 #include <sys/lgrp_user.h>
51 #define DELIMIT_AFF '/' /* lgroup affinity from lgroups */
52 #define DELIMIT_LGRP "," /* lgroups from each other */
53 #define DELIMIT_LWP "/" /* thread/LWP IDs from process ID */
54 #define DELIMIT_RANGE '-' /* range of IDs (eg. lgroup) */
55 #define DELIMIT_AFF_LST ',' /* list of affinities from another list */
58 * Exit values other than EXIT_{SUCCESS,FAILURE}
60 #define EXIT_NONFATAL 2 /* non-fatal errors */
63 * Header and format strings
65 #define HDR_PLGRP_AFF_GET " PID/LWPID HOME AFFINITY\n"
66 #define HDR_PLGRP_AFF_SET " PID/LWPID HOME AFFINITY\n"
67 #define HDR_PLGRP_HOME_GET " PID/LWPID HOME\n"
68 #define HDR_PLGRP_HOME_SET " PID/LWPID HOME\n"
71 * Part of the HDR_PLGRP_AFF_SET header used to calculate space needed to
72 * represent changing home as old => new
74 #define HDR_PLGRP_HOME_CHANGE "HOME "
76 #define FMT_AFF "%d/%s"
77 #define FMT_AFF_STR "%s"
78 #define FMT_HOME "%-6d"
79 #define FMT_NEWHOME "%d => %d"
80 #define FMT_THREAD "%8d/%-8d"
83 * How much to allocate for lgroup bitmap array as it grows
85 #define LGRP_BITMAP_CHUNK 8
88 * Strings that can be given for lgroups
90 #define LGRP_ALL_STR "all"
91 #define LGRP_LEAVES_STR "leaves"
92 #define LGRP_ROOT_STR "root"
95 * Strings corresponding to lgroup affinities
97 #define LGRP_AFF_NONE_STR "none"
98 #define LGRP_AFF_STRONG_STR "strong"
99 #define LGRP_AFF_WEAK_STR "weak"
102 * Invalid value for lgroup affinity
104 #define LGRP_AFF_INVALID -1
107 * Number of args needed for lgroup system call
109 #define LGRPSYS_NARGS 3
111 #ifndef TEXT_DOMAIN /* should be defined by cc -D */
112 #define TEXT_DOMAIN "SYS_TEST" /* use this only if it wasn't */
116 * plgrp(1) operations
118 typedef enum plgrp_ops
{
127 * Arguments specified to plgrp(1) and any state needed to do everything
128 * that plgrp(1) does for one operation from inside Plwp_iter_all()
130 typedef struct plgrp_args
{
131 struct ps_prochandle
*Ph
; /* proc handle for process */
132 const char *lwps
; /* LWPs */
133 lgrp_id_t
*lgrps
; /* lgroups */
134 lgrp_affinity_t
*affs
; /* lgroup affinities */
135 int nlgrps
; /* number of lgroups */
136 int nelements
; /* number of elements */
137 int index
; /* index */
138 int nthreads
; /* threads processed */
139 plgrp_ops_t op
; /* operation */
143 * How many signals caught from terminal
144 * We bail out as soon as possible when interrupt is set
146 static int interrupt
= 0;
149 * How many non-fatal errors ocurred
151 static int nerrors
= 0;
154 * Name of this program
156 static char *progname
;
159 * Root of the lgroup hierarchy
161 static lgrp_id_t root
= LGRP_NONE
;
164 * Bitmap of all lgroups in the system
166 static char *lgrps_bitmap
= NULL
;
169 * Size of lgrps_bitmap array
171 static int lgrps_bitmap_nelements
= 0;
174 * Macro LGRP_VALID returns true when lgrp is present in the system.
176 #define LGRP_VALID(lgrp) (lgrps_bitmap[lgrp] != 0)
180 * Maximum lgroup value.
182 static int max_lgrpid
= LGRP_NONE
;
185 * Total possible number of lgroups
187 #define NLGRPS (max_lgrpid + 1)
193 (void) fprintf(stderr
,
194 gettext("Usage:\t%s [-h] <pid> | <core> [/lwps] ...\n"), progname
);
195 (void) fprintf(stderr
,
196 gettext("\t%s [-F] -a <lgroup list> <pid>[/lwps] ...\n"), progname
);
197 (void) fprintf(stderr
,
198 gettext("\t%s [-F] -A <lgroup list>/none|weak|strong[,...] "
199 " <pid>[/lwps] ...\n"), progname
);
200 (void) fprintf(stderr
,
201 gettext("\t%s [-F] -H <lgroup list> <pid>[/lwps] ...\n"), progname
);
202 (void) fprintf(stderr
,
203 gettext("\n\twhere <lgroup list> is a comma separated list of\n"
204 "\tone or more of the following:\n\n"
206 "\t - Range of lgroup IDs specified as\n"
207 "\t\t<start lgroup ID>-<end lgroup ID>\n"
210 "\t - \"leaves\"\n\n"));
216 * Handler for catching signals from terminal
227 * Return string name for given lgroup affinity
230 lgrp_affinity_string(lgrp_affinity_t aff
)
232 char *rc
= "unknown";
235 case LGRP_AFF_STRONG
:
253 * Add a new lgroup into lgroup array in "arg", growing lgroup and affinity
254 * arrays if necessary
257 lgrps_add_lgrp(plgrp_args_t
*arg
, int id
)
260 if (arg
->nlgrps
== arg
->nelements
) {
261 arg
->nelements
+= LGRP_BITMAP_CHUNK
;
263 arg
->lgrps
= realloc(arg
->lgrps
,
264 arg
->nelements
* sizeof (lgrp_id_t
));
265 if (arg
->lgrps
== NULL
) {
266 (void) fprintf(stderr
, gettext("%s: out of memory\n"),
271 arg
->affs
= realloc(arg
->affs
,
272 arg
->nelements
* sizeof (lgrp_affinity_t
));
274 if (arg
->affs
== NULL
) {
275 (void) fprintf(stderr
, gettext("%s: out of memory\n"),
281 arg
->lgrps
[arg
->nlgrps
] = id
;
282 arg
->affs
[arg
->nlgrps
] = LGRP_AFF_INVALID
;
288 * Return an array having '1' for each lgroup present in given subtree under
289 * specified lgroup in lgroup hierarchy
292 lgrps_bitmap_init(lgrp_cookie_t cookie
, lgrp_id_t lgrpid
, char **bitmap_array
,
293 int *bitmap_nelements
)
300 lgrpid
= lgrp_root(cookie
);
306 * If new lgroup cannot fit, grow the array and fill unused portion
309 while (lgrpid
>= *bitmap_nelements
) {
310 *bitmap_nelements
+= LGRP_BITMAP_CHUNK
;
311 *bitmap_array
= realloc(*bitmap_array
,
312 *bitmap_nelements
* sizeof (char));
313 if (*bitmap_array
== NULL
) {
314 (void) fprintf(stderr
, gettext("%s: out of memory\n"),
318 bzero(*bitmap_array
+ NLGRPS
,
319 (*bitmap_nelements
- NLGRPS
) * sizeof (char));
323 * Insert lgroup into bitmap and update max lgroup ID seen so far
325 (*bitmap_array
)[lgrpid
] = 1;
326 if (lgrpid
> max_lgrpid
)
330 * Get children of specified lgroup and insert descendants of each
333 nchildren
= lgrp_children(cookie
, lgrpid
, NULL
, 0);
335 children
= malloc(nchildren
* sizeof (lgrp_id_t
));
336 if (children
== NULL
) {
337 (void) fprintf(stderr
, gettext("%s: out of memory\n"),
341 if (lgrp_children(cookie
, lgrpid
, children
, nchildren
) !=
347 for (i
= 0; i
< nchildren
; i
++)
348 lgrps_bitmap_init(cookie
, children
[i
], bitmap_array
,
357 * Parse lgroup affinity from given string
359 * Return lgroup affinity or LGRP_AFF_INVALID if string doesn't match any
360 * existing lgroup affinity and return pointer to position just after affinity
363 static lgrp_affinity_t
364 parse_lgrp_affinity(char *string
, char **next
)
366 int rc
= LGRP_AFF_INVALID
;
369 return (LGRP_AFF_INVALID
);
374 if (string
[0] == DELIMIT_AFF
)
378 * Return lgroup affinity matching string
380 if (strncmp(string
, LGRP_AFF_NONE_STR
, strlen(LGRP_AFF_NONE_STR
))
383 *next
= string
+ strlen(LGRP_AFF_NONE_STR
);
384 } else if (strncmp(string
,
385 LGRP_AFF_WEAK_STR
, strlen(LGRP_AFF_WEAK_STR
)) == 0) {
387 *next
= string
+ strlen(LGRP_AFF_WEAK_STR
);
388 } else if (strncmp(string
, LGRP_AFF_STRONG_STR
,
389 strlen(LGRP_AFF_STRONG_STR
)) == 0) {
390 rc
= LGRP_AFF_STRONG
;
391 *next
= string
+ strlen(LGRP_AFF_STRONG_STR
);
399 * Parse lgroups from given string
400 * Returns the set containing all lgroups parsed or NULL.
403 parse_lgrps(lgrp_cookie_t cookie
, plgrp_args_t
*arg
, char *s
)
408 if (cookie
== LGRP_COOKIE_NONE
|| s
== NULL
|| NLGRPS
<= 0)
412 * Parse first lgroup (if any)
414 token
= strtok(s
, DELIMIT_LGRP
);
422 if (isdigit(*token
)) {
430 * Can be <lgroup ID>[-<lgroup ID>]
432 p
= strchr(token
, DELIMIT_RANGE
);
439 for (i
= first
; i
<= last
; i
++) {
441 * Add valid lgroups to lgroup array
443 if ((i
>= 0) && (i
< NLGRPS
) && LGRP_VALID(i
))
444 lgrps_add_lgrp(arg
, i
);
446 (void) fprintf(stderr
,
447 gettext("%s: bad lgroup %d\n"),
452 } else if (strncmp(token
, LGRP_ALL_STR
,
453 strlen(LGRP_ALL_STR
)) == 0) {
455 * Add "all" lgroups to lgroups array
457 for (i
= 0; i
< NLGRPS
; i
++) {
459 lgrps_add_lgrp(arg
, i
);
461 } else if (strncmp(token
, LGRP_ROOT_STR
,
462 strlen(LGRP_ROOT_STR
)) == 0) {
464 root
= lgrp_root(cookie
);
465 lgrps_add_lgrp(arg
, root
);
466 } else if (strncmp(token
, LGRP_LEAVES_STR
,
467 strlen(LGRP_LEAVES_STR
)) == 0) {
469 * Add leaf lgroups to lgroups array
471 for (i
= 0; i
< NLGRPS
; i
++) {
473 lgrp_children(cookie
, i
, NULL
, 0) == 0)
474 lgrps_add_lgrp(arg
, i
);
479 } while (token
= strtok(NULL
, DELIMIT_LGRP
));
485 * Print array of lgroup IDs, collapsing any consecutive runs of IDs into a
486 * range (eg. 2,3,4 into 2-4)
489 print_lgrps(lgrp_id_t
*lgrps
, int nlgrps
)
496 * Initial range consists of the first element
498 start
= end
= lgrps
[0];
500 for (i
= 1; i
< nlgrps
; i
++) {
504 if (lgrpid
== end
+ 1) {
506 * Got consecutive lgroup ID, so extend end of range
507 * without printing anything since the range may extend
513 * Next lgroup ID is not consecutive, so print lgroup
516 if (end
== start
) { /* same value */
517 (void) printf("%d,", (int)start
);
518 } else if (end
> start
+ 1) { /* range */
519 (void) printf("%d-%d,", (int)start
, (int)end
);
520 } else { /* different values */
521 (void) printf("%d,%d,", (int)start
, (int)end
);
525 * Try finding consecutive range starting from this
528 start
= end
= lgrpid
;
533 * Print last lgroup ID(s)
536 (void) printf("%d", (int)start
);
537 } else if (end
> start
+ 1) {
538 (void) printf("%d-%d", (int)start
, (int)end
);
540 (void) printf("%d,%d", (int)start
, (int)end
);
545 * Print lgroup affinities given array of lgroups, corresponding array of
546 * affinities, and number of elements.
547 * Skip any lgroups set to LGRP_NONE or having invalid affinity.
550 print_affinities(lgrp_id_t
*lgrps
, lgrp_affinity_t
*affs
, int nelements
)
553 lgrp_id_t
*lgrps_none
;
554 lgrp_id_t
*lgrps_strong
;
555 lgrp_id_t
*lgrps_weak
;
560 nlgrps_strong
= nlgrps_weak
= nlgrps_none
= 0;
562 lgrps_strong
= malloc(nelements
* sizeof (lgrp_id_t
));
563 lgrps_weak
= malloc(nelements
* sizeof (lgrp_id_t
));
564 lgrps_none
= malloc(nelements
* sizeof (lgrp_id_t
));
566 if (lgrps_strong
== NULL
|| lgrps_weak
== NULL
|| lgrps_none
== NULL
) {
567 (void) fprintf(stderr
, gettext("%s: out of memory\n"),
574 * Group lgroups by affinity
576 for (i
= 0; i
< nelements
; i
++) {
577 lgrp_id_t lgrpid
= lgrps
[i
];
580 * Skip any lgroups set to LGRP_NONE
582 if (lgrpid
== LGRP_NONE
)
586 case LGRP_AFF_STRONG
:
587 lgrps_strong
[nlgrps_strong
++] = lgrpid
;
590 lgrps_weak
[nlgrps_weak
++] = lgrpid
;
593 lgrps_none
[nlgrps_none
++] = lgrpid
;
597 * Skip any lgroups with invalid affinity.
604 * Print all lgroups with same affinity together
607 print_lgrps(lgrps_strong
, nlgrps_strong
);
608 (void) printf("/%s", lgrp_affinity_string(LGRP_AFF_STRONG
));
609 if (nlgrps_weak
|| nlgrps_none
)
610 (void) printf("%c", DELIMIT_AFF_LST
);
614 print_lgrps(lgrps_weak
, nlgrps_weak
);
615 (void) printf("/%s", lgrp_affinity_string(LGRP_AFF_WEAK
));
617 (void) printf("%c", DELIMIT_AFF_LST
);
621 print_lgrps(lgrps_none
, nlgrps_none
);
622 (void) printf("/%s", lgrp_affinity_string(LGRP_AFF_NONE
));
632 * Print heading for specified operation
635 print_heading(plgrp_ops_t op
)
639 case PLGRP_AFFINITY_GET
:
640 (void) printf(HDR_PLGRP_AFF_GET
);
643 case PLGRP_AFFINITY_SET
:
644 (void) printf(HDR_PLGRP_AFF_SET
);
648 (void) printf(HDR_PLGRP_HOME_GET
);
652 (void) printf(HDR_PLGRP_HOME_SET
);
661 * Use /proc to call lgrp_affinity_get() in another process
663 static lgrp_affinity_t
664 Plgrp_affinity_get(struct ps_prochandle
*Ph
, idtype_t idtype
, id_t id
,
667 lgrp_affinity_args_t args
;
676 * Fill in arguments needed for syscall(SYS_lgrpsys,
677 * LGRP_SYS_AFFINITY_GET, 0, &args)
679 syscall
= SYS_lgrpsys
;
681 args
.idtype
= idtype
;
684 args
.aff
= LGRP_AFF_INVALID
;
687 * Fill out /proc argument descriptors for syscall(SYS_lgrpsys,
688 * LGRP_SYS_AFFINITY_GET, idtype, id)
690 Pnargs
= LGRPSYS_NARGS
;
692 Pargdp
->arg_value
= LGRP_SYS_AFFINITY_GET
;
693 Pargdp
->arg_object
= NULL
;
694 Pargdp
->arg_type
= AT_BYVAL
;
695 Pargdp
->arg_inout
= AI_INPUT
;
696 Pargdp
->arg_size
= 0;
699 Pargdp
->arg_value
= 0;
700 Pargdp
->arg_object
= NULL
;
701 Pargdp
->arg_type
= AT_BYVAL
;
702 Pargdp
->arg_inout
= AI_INPUT
;
703 Pargdp
->arg_size
= 0;
706 Pargdp
->arg_value
= 0;
707 Pargdp
->arg_object
= &args
;
708 Pargdp
->arg_type
= AT_BYREF
;
709 Pargdp
->arg_inout
= AI_INPUT
;
710 Pargdp
->arg_size
= sizeof (lgrp_affinity_args_t
);
714 * Have agent LWP call syscall with appropriate arguments in target
717 Pretval
= Psyscall(Ph
, &retval
, syscall
, Pnargs
, &Pargd
[0]);
719 errno
= (Pretval
< 0) ? ENOSYS
: Pretval
;
720 return (LGRP_AFF_INVALID
);
723 return (retval
.sys_rval1
);
728 * Use /proc to call lgrp_affinity_set() in another process
731 Plgrp_affinity_set(struct ps_prochandle
*Ph
, idtype_t idtype
, id_t id
,
732 lgrp_id_t lgrp
, lgrp_affinity_t aff
)
734 lgrp_affinity_args_t args
;
743 * Fill in arguments needed for syscall(SYS_lgrpsys,
744 * LGRP_SYS_AFFINITY_SET, 0, &args)
746 syscall
= SYS_lgrpsys
;
748 args
.idtype
= idtype
;
754 * Fill out /proc argument descriptors for syscall(SYS_lgrpsys,
755 * LGRP_SYS_AFFINITY_SET, idtype, id)
757 Pnargs
= LGRPSYS_NARGS
;
759 Pargdp
->arg_value
= LGRP_SYS_AFFINITY_SET
;
760 Pargdp
->arg_object
= NULL
;
761 Pargdp
->arg_type
= AT_BYVAL
;
762 Pargdp
->arg_inout
= AI_INPUT
;
763 Pargdp
->arg_size
= 0;
766 Pargdp
->arg_value
= 0;
767 Pargdp
->arg_object
= NULL
;
768 Pargdp
->arg_type
= AT_BYVAL
;
769 Pargdp
->arg_inout
= AI_INPUT
;
770 Pargdp
->arg_size
= 0;
773 Pargdp
->arg_value
= 0;
774 Pargdp
->arg_object
= &args
;
775 Pargdp
->arg_type
= AT_BYREF
;
776 Pargdp
->arg_inout
= AI_INPUT
;
777 Pargdp
->arg_size
= sizeof (lgrp_affinity_args_t
);
781 * Have agent LWP call syscall with appropriate arguments in
784 Pretval
= Psyscall(Ph
, &retval
, syscall
, Pnargs
, &Pargd
[0]);
786 errno
= (Pretval
< 0) ? ENOSYS
: Pretval
;
790 return (retval
.sys_rval1
);
794 * Use /proc to call lgrp_home() in another process
797 Plgrp_home(struct ps_prochandle
*Ph
, idtype_t idtype
, id_t id
)
807 * Fill in arguments needed for syscall(SYS_lgrpsys,
808 * LGRP_SYS_HOME, idtype, id)
810 syscall
= SYS_lgrpsys
;
813 * Fill out /proc argument descriptors for syscall(SYS_lgrpsys,
814 * LGRP_SYS_HOME, idtype, id)
816 Pnargs
= LGRPSYS_NARGS
;
818 Pargdp
->arg_value
= LGRP_SYS_HOME
;
819 Pargdp
->arg_object
= NULL
;
820 Pargdp
->arg_type
= AT_BYVAL
;
821 Pargdp
->arg_inout
= AI_INPUT
;
822 Pargdp
->arg_size
= 0;
825 Pargdp
->arg_value
= idtype
;
826 Pargdp
->arg_object
= NULL
;
827 Pargdp
->arg_type
= AT_BYVAL
;
828 Pargdp
->arg_inout
= AI_INPUT
;
829 Pargdp
->arg_size
= 0;
832 Pargdp
->arg_value
= id
;
833 Pargdp
->arg_object
= NULL
;
834 Pargdp
->arg_type
= AT_BYVAL
;
835 Pargdp
->arg_inout
= AI_INPUT
;
836 Pargdp
->arg_size
= 0;
840 * Have agent LWP call syscall with appropriate arguments in
843 Pretval
= Psyscall(Ph
, &retval
, syscall
, Pnargs
, &Pargd
[0]);
845 errno
= (Pretval
< 0) ? ENOSYS
: Pretval
;
849 return (retval
.sys_rval1
);
853 * Use /proc to call lgrp_affinity_set(3LGRP) to set home lgroup of given
857 Plgrp_home_set(struct ps_prochandle
*Ph
, idtype_t idtype
, id_t id
,
860 return (Plgrp_affinity_set(Ph
, idtype
, id
, lgrp
,
866 * Do plgrp(1) operation on specified thread
869 do_op(plgrp_args_t
*plgrp_args
, id_t pid
, id_t lwpid
,
870 const lwpsinfo_t
*lwpsinfo
)
872 lgrp_affinity_t
*affs
;
873 lgrp_affinity_t
*cur_affs
;
876 lgrp_affinity_t
*init_affs
;
878 lgrp_id_t
*lgrps_changed
;
882 struct ps_prochandle
*Ph
;
886 * No args, so nothing to do.
888 if (plgrp_args
== NULL
)
892 * Unpack plgrp(1) arguments and state needed to process this LWP
895 lgrps
= plgrp_args
->lgrps
;
896 affs
= plgrp_args
->affs
;
897 nlgrps
= plgrp_args
->nlgrps
;
899 switch (plgrp_args
->op
) {
903 * Get and display home lgroup for given LWP
905 home
= lwpsinfo
->pr_lgrp
;
906 (void) printf(FMT_HOME
"\n", (int)home
);
909 case PLGRP_AFFINITY_GET
:
911 * Get and display this LWP's home lgroup and affinities
912 * for specified lgroups
914 home
= lwpsinfo
->pr_lgrp
;
915 (void) printf(FMT_HOME
, (int)home
);
918 * Collect affinity values
920 for (i
= 0; i
< nlgrps
; i
++) {
921 affs
[i
] = Plgrp_affinity_get(Ph
, P_LWPID
, lwpid
,
924 if (affs
[i
] == LGRP_AFF_INVALID
) {
926 (void) fprintf(stderr
,
927 gettext("%s: cannot get affinity"
928 " for lgroup %d for %d/%d: %s\n"),
929 progname
, lgrps
[i
], pid
, lwpid
,
935 * Print affinities for each type.
937 print_affinities(lgrps
, affs
, nlgrps
);
944 * Get home lgroup before and after setting it and display
945 * change. If more than one lgroup and one LWP are specified,
946 * then home LWPs to lgroups in round robin fashion.
948 old_home
= lwpsinfo
->pr_lgrp
;
950 i
= plgrp_args
->index
;
951 if (Plgrp_home_set(Ph
, P_LWPID
, lwpid
, lgrps
[i
]) != 0) {
953 (void) fprintf(stderr
,
954 gettext("%s: cannot set home lgroup of %d/%d"
955 " to lgroup %d: %s\n"),
956 progname
, pid
, lwpid
, lgrps
[i
],
961 int width
= strlen(HDR_PLGRP_HOME_CHANGE
);
963 home
= Plgrp_home(Ph
, P_LWPID
, lwpid
);
966 (void) fprintf(stderr
,
967 gettext("%s cannot get home lgroup for"
969 progname
, pid
, lwpid
, strerror(errno
));
973 len
= printf(FMT_NEWHOME
, (int)old_home
, (int)home
);
975 (void) printf("%*c\n", (int)(width
- len
), ' ');
978 plgrp_args
->index
= (i
+ 1) % nlgrps
;
982 case PLGRP_AFFINITY_SET
:
984 * Set affinities for specified lgroups and print old and new
985 * affinities and any resulting change in home lgroups
989 * Get initial home lgroup as it may change.
991 old_home
= lwpsinfo
->pr_lgrp
;
994 * Need to allocate arrays indexed by lgroup (ID) for
995 * affinities and lgroups because user may specify affinity
996 * for same lgroup multiple times....
998 * Keeping these arrays by lgroup (ID) eliminates any
999 * duplication and makes it easier to just print initial and
1000 * final lgroup affinities (instead of trying to keep a list
1001 * of lgroups specified which may include duplicates)
1003 init_affs
= malloc(NLGRPS
* sizeof (lgrp_affinity_t
));
1004 cur_affs
= malloc(NLGRPS
* sizeof (lgrp_affinity_t
));
1005 lgrps_changed
= malloc(NLGRPS
* sizeof (lgrp_id_t
));
1007 if (init_affs
== NULL
|| cur_affs
== NULL
||
1008 lgrps_changed
== NULL
) {
1009 (void) fprintf(stderr
, gettext("%s: out of memory\n"),
1011 Prelease(Ph
, PRELEASE_RETAIN
);
1012 if (init_affs
!= NULL
)
1014 if (cur_affs
!= NULL
)
1017 return (EXIT_NONFATAL
);
1021 * Initialize current and initial lgroup affinities and
1024 for (lgrpid
= 0; lgrpid
< NLGRPS
; lgrpid
++) {
1026 if (!LGRP_VALID(lgrpid
)) {
1027 init_affs
[lgrpid
] = LGRP_AFF_INVALID
;
1030 Plgrp_affinity_get(Ph
, P_LWPID
,
1033 if (init_affs
[lgrpid
] == LGRP_AFF_INVALID
) {
1035 (void) fprintf(stderr
,
1036 gettext("%s: cannot get"
1037 " affinity for lgroup %d"
1038 " for %d/%d: %s\n"),
1039 progname
, lgrpid
, pid
, lwpid
,
1044 cur_affs
[lgrpid
] = init_affs
[lgrpid
];
1045 lgrps_changed
[lgrpid
] = LGRP_NONE
;
1049 * Change affinities.
1051 for (i
= 0; i
< nlgrps
; i
++) {
1052 lgrp_affinity_t aff
= affs
[i
];
1057 * If the suggested affinity is the same as the current
1058 * one, skip this lgroup.
1060 if (aff
== cur_affs
[lgrpid
])
1064 * Set affinity to the new value
1066 if (Plgrp_affinity_set(Ph
, P_LWPID
, lwpid
, lgrpid
,
1069 (void) fprintf(stderr
,
1070 gettext("%s: cannot set"
1071 " %s affinity for lgroup %d"
1072 " for %d/%d: %s\n"),
1073 progname
, lgrp_affinity_string(aff
),
1080 * Get the new value and verify that it changed as
1084 Plgrp_affinity_get(Ph
, P_LWPID
, lwpid
, lgrpid
);
1086 if (cur_affs
[lgrpid
] == LGRP_AFF_INVALID
) {
1088 (void) fprintf(stderr
,
1089 gettext("%s: cannot get"
1090 " affinity for lgroup %d"
1091 " for %d/%d: %s\n"),
1092 progname
, lgrpid
, pid
, lwpid
,
1097 if (aff
!= cur_affs
[lgrpid
]) {
1098 (void) fprintf(stderr
,
1099 gettext("%s: affinity for"
1100 " lgroup %d is set to %d instead of %d"
1102 progname
, lgrpid
, cur_affs
[lgrpid
], aff
,
1109 * Compare current and initial affinities and mark lgroups with
1110 * changed affinities.
1113 for (lgrpid
= 0; lgrpid
< NLGRPS
; lgrpid
++) {
1114 if (init_affs
[lgrpid
] != cur_affs
[lgrpid
]) {
1115 lgrps_changed
[lgrpid
] = lgrpid
;
1120 if (nchanged
== 0) {
1122 * Nothing changed, so just print current affinities for
1123 * specified lgroups.
1125 for (i
= 0; i
< nlgrps
; i
++) {
1126 lgrps_changed
[lgrps
[i
]] = lgrps
[i
];
1129 (void) printf("%-*d",
1130 (int)strlen(HDR_PLGRP_HOME_CHANGE
),
1133 print_affinities(lgrps_changed
, cur_affs
, NLGRPS
);
1134 (void) printf("\n");
1136 int width
= strlen(HDR_PLGRP_HOME_CHANGE
);
1139 * Some lgroup affinities changed, so display old
1140 * and new home lgroups for thread and its old and new
1141 * affinities for affected lgroups
1143 home
= Plgrp_home(Ph
, P_LWPID
, lwpid
);
1145 (void) fprintf(stderr
,
1146 gettext("%s: cannot get home"
1147 " for %d/%d: %s\n"),
1148 progname
, pid
, lwpid
, strerror(errno
));
1151 if (old_home
!= home
) {
1155 * Fit string into fixed width
1157 len
= printf(FMT_NEWHOME
,
1158 (int)old_home
, (int)home
);
1160 (void) printf("%*c", width
- len
, ' ');
1162 (void) printf("%-*d", width
, (int)home
);
1166 * Print change in affinities from old to new
1168 print_affinities(lgrps_changed
, init_affs
, NLGRPS
);
1169 (void) printf(" => ");
1170 print_affinities(lgrps_changed
, cur_affs
, NLGRPS
);
1171 (void) printf("\n");
1174 free(lgrps_changed
);
1189 * Routine called by Plwp_iter_all() as it iterates through LWPs of another
1194 Plwp_iter_handler(void *arg
, const lwpstatus_t
*lwpstatus
,
1195 const lwpsinfo_t
*lwpsinfo
)
1198 struct ps_prochandle
*Ph
;
1199 const pstatus_t
*pstatus
;
1200 plgrp_args_t
*plgrp_args
;
1203 * Nothing to do if no arguments
1205 if (arg
== NULL
|| interrupt
)
1209 * Unpack plgrp(1) arguments and state needed to process this LWP
1212 Ph
= plgrp_args
->Ph
;
1215 * Just return if no /proc handle for process
1220 pstatus
= Pstatus(Ph
);
1223 * Skip agent LWP and any LWPs that weren't specified
1225 lwpid
= lwpsinfo
->pr_lwpid
;
1226 if (lwpid
== pstatus
->pr_agentid
||
1227 !proc_lwp_in_set(plgrp_args
->lwps
, lwpid
))
1230 plgrp_args
->nthreads
++;
1233 * Do all plgrp(1) operations specified on given thread
1235 (void) printf(FMT_THREAD
" ", (int)pstatus
->pr_pid
, (int)lwpid
);
1236 return (do_op(plgrp_args
, pstatus
->pr_pid
, lwpid
, lwpsinfo
));
1240 * Get target process specified in "pidstring" argument to do operation(s)
1241 * specified in "plgrp_todo" using /proc and agent LWP
1244 do_process(char *pidstring
, plgrp_args_t
*plgrp_todo
, int force
)
1248 struct ps_prochandle
*Ph
;
1251 * Nothing to do, so return.
1253 if (plgrp_todo
== NULL
|| interrupt
)
1257 * Grab target process or core and return
1258 * /proc handle for process and string of LWP
1261 Ph
= proc_arg_xgrab(pidstring
, NULL
,
1262 PR_ARG_ANY
, force
| PGRAB_RETAIN
| PGRAB_NOSTOP
, &error
, &lwps
);
1264 (void) fprintf(stderr
,
1265 gettext("%s: Unable to grab process %s: %s\n"),
1266 progname
, pidstring
, Pgrab_error(error
));
1272 * Fill in remaining plgrp(1) arguments and state needed to do
1273 * plgrp(1) operation(s) on desired LWPs in our handler
1274 * called by Plwp_iter_all() as it iterates over LWPs
1277 plgrp_todo
->Ph
= Ph
;
1278 plgrp_todo
->lwps
= lwps
;
1281 * Iterate over LWPs in process and do specified
1282 * operation(s) on those specified
1284 if (Plwp_iter_all(Ph
, Plwp_iter_handler
, plgrp_todo
) != 0) {
1285 (void) fprintf(stderr
,
1286 gettext("%s: error iterating over threads\n"),
1291 Prelease(Ph
, PRELEASE_RETAIN
);
1296 * Parse command line and kick off any resulting actions
1298 * plgrp(1) has the following command line syntax:
1300 * plgrp [-h] <pid> | <core> [/lwps] ...
1301 * plgrp [-F] -a <lgroup>,... <pid>[/lwps] ...
1302 * plgrp [-F] -H <lgroup>,... <pid>[/lwps] ...
1303 * plgrp [-F] -A <lgroup>,... [/none|weak|strong] ... <pid>[/lwps] ...
1305 * where <lgroup> is an lgroup ID, "all", "root", "leaves".
1308 main(int argc
, char *argv
[])
1310 lgrp_affinity_t aff
;
1313 lgrp_cookie_t cookie
;
1317 plgrp_args_t plgrp_todo
;
1320 (void) setlocale(LC_ALL
, "");
1321 (void) textdomain(TEXT_DOMAIN
);
1326 * Get name of program
1328 progname
= basename(argv
[0]);
1331 * Not much to do when only name of program given
1337 * Catch signals from terminal, so they can be handled asynchronously
1338 * when we're ready instead of when we're not (;-)
1340 if (sigset(SIGHUP
, SIG_IGN
) == SIG_DFL
)
1341 (void) sigset(SIGHUP
, intr
);
1342 if (sigset(SIGINT
, SIG_IGN
) == SIG_DFL
)
1343 (void) sigset(SIGINT
, intr
);
1344 if (sigset(SIGQUIT
, SIG_IGN
) == SIG_DFL
)
1345 (void) sigset(SIGQUIT
, intr
);
1346 (void) sigset(SIGPIPE
, intr
);
1347 (void) sigset(SIGTERM
, intr
);
1350 * Take snapshot of lgroup hierarchy
1352 cookie
= lgrp_init(LGRP_VIEW_OS
);
1353 if (cookie
== LGRP_COOKIE_NONE
) {
1354 (void) fprintf(stderr
,
1355 gettext("%s: Fatal error: cannot get lgroup"
1356 " information from the OS: %s\n"),
1357 progname
, strerror(errno
));
1358 return (EXIT_FAILURE
);
1361 root
= lgrp_root(cookie
);
1362 lgrps_bitmap_init(cookie
, root
, &lgrps_bitmap
, &lgrps_bitmap_nelements
);
1365 * Remember arguments and state needed to do plgrp(1) operation
1368 bzero(&plgrp_todo
, sizeof (plgrp_args_t
));
1369 plgrp_todo
.op
= PLGRP_HOME_GET
;
1376 while (!interrupt
&& (c
= getopt(argc
, argv
, "a:A:FhH:")) != -1) {
1378 * Parse option and only allow one option besides -F to be
1383 case 'h': /* Get home lgroup */
1385 * Only allow one option (besides -F) to be specified
1388 usage(EXIT_FAILURE
);
1391 plgrp_todo
.op
= PLGRP_HOME_GET
;
1394 case 'H': /* Set home lgroup */
1397 * Fail if already specified option (besides -F)
1398 * or no more arguments
1400 if (opt_seen
|| optind
>= argc
) {
1401 usage(EXIT_FAILURE
);
1405 plgrp_todo
.op
= PLGRP_HOME_SET
;
1407 if (parse_lgrps(cookie
, &plgrp_todo
, optarg
) < 0)
1408 usage(EXIT_FAILURE
);
1410 /* If there are no valid lgroups exit immediately */
1411 if (plgrp_todo
.nlgrps
== 0) {
1412 (void) fprintf(stderr
,
1413 gettext("%s: no valid lgroups"
1414 " specified for -%c\n\n"),
1416 usage(EXIT_FAILURE
);
1421 case 'a': /* Get lgroup affinity */
1424 * Fail if already specified option (besides -F)
1425 * or no more arguments
1427 if (opt_seen
|| optind
>= argc
) {
1428 usage(EXIT_FAILURE
);
1432 plgrp_todo
.op
= PLGRP_AFFINITY_GET
;
1434 if (parse_lgrps(cookie
, &plgrp_todo
, optarg
) < 0)
1435 usage(EXIT_FAILURE
);
1437 /* If there are no valid lgroups exit immediately */
1438 if (plgrp_todo
.nlgrps
== 0) {
1439 (void) fprintf(stderr
,
1440 gettext("%s: no valid lgroups specified"
1443 usage(EXIT_FAILURE
);
1448 case 'A': /* Set lgroup affinity */
1451 * Fail if already specified option (besides -F)
1452 * or no more arguments
1454 if (opt_seen
|| optind
>= argc
) {
1455 usage(EXIT_FAILURE
);
1459 plgrp_todo
.op
= PLGRP_AFFINITY_SET
;
1462 * 'affstring' is the unparsed prtion of the affinity
1463 * specification like 1,2/none,2/weak,0/strong
1465 * 'next' is the next affinity specification to parse.
1468 while (affstring
!= NULL
&& strlen(affstring
) > 0) {
1472 * affstring points to the first affinity
1473 * specification. Split the string by
1474 * DELIMIT_AFF separator and parse lgroups and
1475 * affinity value separately.
1477 s
= strchr(affstring
, DELIMIT_AFF
);
1479 (void) fprintf(stderr
,
1480 gettext("%s: invalid "
1482 progname
, affstring
);
1483 usage(EXIT_FAILURE
);
1486 aff
= parse_lgrp_affinity(s
, &next
);
1487 if (aff
== LGRP_AFF_INVALID
) {
1488 (void) fprintf(stderr
,
1489 gettext("%s: invalid "
1491 progname
, affstring
);
1492 usage(EXIT_FAILURE
);
1496 * next should either point to the empty string
1497 * or to the DELIMIT_AFF_LST separator.
1499 if (*next
!= '\0') {
1500 if (*next
!= DELIMIT_AFF_LST
) {
1501 (void) fprintf(stderr
,
1502 gettext("%s: invalid "
1505 usage(EXIT_FAILURE
);
1513 * Now parse the list of lgroups
1515 if (parse_lgrps(cookie
, &plgrp_todo
,
1517 usage(EXIT_FAILURE
);
1521 * Set desired affinity for specified lgroup to
1522 * the specified affinity.
1524 for (i
= 0; i
< plgrp_todo
.nlgrps
; i
++) {
1525 if (plgrp_todo
.affs
[i
] ==
1527 plgrp_todo
.affs
[i
] = aff
;
1531 * We processed the leftmost element of the
1532 * list. Advance affstr to the remaining part of
1533 * the list. and repeat.
1539 * If there are no valid lgroups, exit immediately
1541 if (plgrp_todo
.nlgrps
== 0) {
1542 (void) fprintf(stderr
,
1543 gettext("%s: no valid lgroups specified "
1544 "for -%c\n\n"), progname
, c
);
1545 usage(EXIT_FAILURE
);
1550 case 'F': /* Force */
1553 * Only allow one occurrence
1556 usage(EXIT_FAILURE
);
1560 * Set flag to force /proc to grab process even though
1561 * it's been grabbed by another process already
1563 Fflag
= PGRAB_FORCE
;
1566 case '?': /* Unrecognized option */
1568 usage(EXIT_FAILURE
);
1575 * Should have more arguments left at least for PID or core
1578 usage(EXIT_FAILURE
);
1580 (void) lgrp_fini(cookie
);
1583 * Print heading and process each [pid | core]/lwps argument
1585 print_heading(plgrp_todo
.op
);
1586 (void) proc_initstdio();
1588 for (i
= optind
; i
< argc
&& !interrupt
; i
++) {
1589 (void) proc_flushstdio();
1590 do_process(argv
[i
], &plgrp_todo
, Fflag
);
1593 (void) proc_finistdio();
1595 if (plgrp_todo
.nthreads
== 0) {
1596 (void) fprintf(stderr
, gettext("%s: no matching LWPs found\n"),
1600 return ((nerrors
||interrupt
) ? EXIT_NONFATAL
: EXIT_SUCCESS
);