[prev in list] [next in list] [prev in thread] [next in thread]
List: busybox
Subject: Re: [PATCH] util-linux/taskset: add support for taking/printing CPU list (-c option)
From: Fryderyk Wrobel <frd1996 () gmail ! com>
Date: 2019-11-02 17:23:36
Message-ID: CAL25=yFWb2zAmtYb3Pnibef+mzazohtPUT3sKHBf2VO-QK76Mg () mail ! gmail ! com
[Download RAW message or body]
Works for me. Thanks!
2019-11-01 14:48 GMT, Denys Vlasenko <vda.linux@googlemail.com>:
> Applied a modified version, please try current git.
>
> On Wed, Oct 30, 2019 at 6:55 PM Fryderyk Wrobel <frd1996@gmail.com> wrote:
>>
>> Hi,
>>
>> This patch implements '-c' option in taskset. With this option taskset
>> will
>> print or take the affinity as CPUs list, for example: "1,3,5-7".
>>
>> Limitations:
>> * Pattern specifiers after a range (e.g. "0-255:2/64") are not
>> supported.
>> * Leading/trailing white-spaces are not allowed, e.g. list " 1,2 " will
>> fail.
>>
>> Kind Regards,
>> Fryderyk
>>
>> taskset: make CPU list support an optional feature
>>
>> function old new delta
>> taskset_main 598 1035 +437
>> .rodata 158112 158151 +39
>> packed_usage 33417 33419 +2
>> ------------------------------------------------------------------------------
>> (add/remove: 0/0 grow/shrink: 3/0 up/down: 478/0) Total: 478
>> bytes
>>
>> diff --git a/util-linux/taskset.c b/util-linux/taskset.c
>> index ed8878ad4..c12728802 100644
>> --- a/util-linux/taskset.c
>> +++ b/util-linux/taskset.c
>> @@ -20,16 +20,29 @@
>> //config: Needed for machines with more than 32-64 CPUs:
>> //config: affinity parameter 0xHHHHHHHHHHHHHHHHHHHH can be
>> arbitrarily long
>> //config: in this case. Otherwise, it is limited to sizeof(long).
>> +//config:
>> +//config:config FEATURE_TASKSET_CPULIST
>> +//config: bool "CPU list support (-c option)"
>> +//config: default n
>> +//config: depends on TASKSET
>> +//config: help
>> +//config: Add support for taking/printing affinity as CPU list when
>> '-c'
>> +//config: option is used. For example, it prints '0-3,7' instead of
>> mask '8f'.
>> +//config:
>> +
>>
>> //applet:IF_TASKSET(APPLET_NOEXEC(taskset, taskset, BB_DIR_USR_BIN,
>> BB_SUID_DROP, taskset))
>>
>> //kbuild:lib-$(CONFIG_TASKSET) += taskset.o
>>
>> //usage:#define taskset_trivial_usage
>> -//usage: "[-p] [HEXMASK] PID | PROG ARGS"
>> +//usage: IF_FEATURE_TASKSET_CPULIST("[-c] ") "[-p] [HEXMASK"
>> IF_FEATURE_TASKSET_CPULIST("|LIST") "] PID | PROG ARGS"
>> //usage:#define taskset_full_usage "\n\n"
>> //usage: "Set or get CPU affinity\n"
>> //usage: "\n -p Operate on an existing PID"
>> +//usage: IF_FEATURE_TASKSET_CPULIST(
>> +//usage: "\n -c Display and specify CPUs in list format"
>> +//usage: )
>> //usage:
>> //usage:#define taskset_example_usage
>> //usage: "$ taskset 0x7 ./dgemm_test&\n"
>> @@ -45,7 +58,6 @@
>> * Not yet implemented:
>> * -a/--all-tasks (affect all threads)
>> * needs to get TIDs from /proc/PID/task/ and use _them_ as "pid" in
>> sched_setaffinity(pid)
>> - * -c/--cpu-list (specify CPUs via "1,3,5-7")
>> */
>>
>> #include <sched.h>
>> @@ -87,6 +99,117 @@ static unsigned long long from_mask(ul *mask,
>> unsigned sz_in_bytes UNUSED_PARAM)
>> }
>> #endif
>>
>> +#if ENABLE_FEATURE_TASKSET_CPULIST
>> +
>> +/*
>> + * Parse the CPU list and set the mask accordingly.
>> + *
>> + * The list element can be either a CPU index or a range of CPU indices.
>> + * Example: "1,3,5-7".
>> + *
>> + * note1: pattern specifiers after a range (e.g. 0-255:2/64) are not
>> supported
>> + * note2: leading/trailing white-spaces are not allowed
>> + */
>> +static int parse_cpulist(ul *mask, unsigned max, const char *s)
>> +{
>> + enum parser_state {
>> + RDY, /* Ready */
>> + LD0, /* Loading first number */
>> + LD1 /* Loading second number */
>> + };
>> + enum parser_state state = RDY;
>> + unsigned v[2] = { 0, 0 };
>> + unsigned i;
>> + char c;
>> +
>> + /* Nesting switch statements is not the prettiest thing in the
>> + * world but this one produces a bit shorter code vs if/else
>> + * when compiled with -O2/-O3 on x86_64 */
>> + do {
>> + c = *s++;
>> +
>> + switch (c) {
>> + case '0' ... '9':
>> + /* Append a digit to the current number */
>> + switch (state) {
>> + case RDY:
>> + v[0] = v[1] = 0;
>> + state = LD0;
>> + /* fall through */
>> + case LD0:
>> + v[0] = 10 * v[0] + c - '0';
>> + break;
>> + case LD1:
>> + v[1] = 10 * v[1] + c - '0';
>> + break;
>> + }
>> + break;
>> +
>> + case '-':
>> + /* It may be a range */
>> + if (state != LD0)
>> + return -1;
>> + state = LD1; /* Move to the
>> second number */
>> + break;
>> +
>> + case ',':
>> + case '\0':
>> + /* End of number/range */
>> + switch (state) {
>> + case LD0: /* Have a single
>> number loaded */
>> + v[1] = v[0]; /* Make it a range:
>> N-N */
>> + /* fall through */
>> + case LD1: /* Have two numbers
>> loaded */
>> + if (v[1] < v[0])
>> + return -1; /* Bad range, e.g.
>> 3-1 */
>> +
>> + for (i = v[0]; i <= v[1] && i < max; i++)
>> + mask[i / BITS_UL] |= (1UL << (i &
>> MASK_UL));
>> +
>> + state = RDY; /* Try to load next
>> number/range */
>> + break;
>> + default:
>> + return -1;
>> + }
>> + break;
>> +
>> + default:
>> + return -1;
>> + }
>> + } while (c != '\0');
>> +
>> + return 0;
>> +}
>> +
>> +static void print_cpulist(const ul *mask, unsigned max)
>> +{
>> + const char *delim = "";
>> + unsigned i, j;
>> +
>> +#define MASK_ISSET(m, b) (m[(b) / BITS_UL] & (1UL << ((b) & MASK_UL)))
>> +
>> + for (i = 0; i < max; i++) {
>> + if (MASK_ISSET(mask, i)) {
>> + for (j = i + 1; j < max && MASK_ISSET(mask, j);
>> j++) {}
>> + j--;
>> +
>> + if (i == j) {
>> + printf("%s%u", delim, i);
>> + } else {
>> + printf("%s%u-%u", delim, i, j);
>> + i = j;
>> + }
>> +
>> + delim=",";
>> + }
>> + }
>> +
>> + putchar('\n');
>> +#undef MASK_ISSET
>> +}
>> +
>> +#endif /* ENABLE_FEATURE_TASKSET_CPULIST */
>> +
>> static unsigned long *get_aff(int pid, unsigned *sz)
>> {
>> int r;
>> @@ -114,20 +237,22 @@ int taskset_main(int argc UNUSED_PARAM, char
>> **argv)
>> ul *mask;
>> unsigned mask_size_in_bytes;
>> pid_t pid = 0;
>> - unsigned opt_p;
>> + unsigned opts;
>> const char *current_new;
>> char *aff;
>>
>> + enum { OPT_p = 1, OPT_c = 2 };
>> +
>> /* NB: we mimic util-linux's taskset: -p does not take
>> * an argument, i.e., "-pN" is NOT valid, only "-p N"!
>> * Indeed, util-linux-2.13-pre7 uses:
>> * getopt_long(argc, argv, "+pchV", ...), not "...p:..." */
>>
>> - opt_p = getopt32(argv, "^+" "p" "\0" "-1" /* at least 1 arg */);
>> + opts = getopt32(argv, "^+" "p" IF_FEATURE_TASKSET_CPULIST("c")
>> "\0"
>> "-1" /* at least 1 arg */);
>> argv += optind;
>>
>> aff = *argv++;
>> - if (opt_p) {
>> + if (opts & OPT_p) {
>> char *pid_str = aff;
>> if (*argv) { /* "-p <aff> <pid> ...rest.is.ignored..." */
>> pid_str = *argv; /* NB: *argv != NULL in this case
>> */
>> @@ -144,9 +269,16 @@ int taskset_main(int argc UNUSED_PARAM, char **argv)
>> current_new = "current";
>> print_aff:
>> mask = get_aff(pid, &mask_size_in_bytes);
>> - if (opt_p) {
>> - printf("pid %d's %s affinity mask:
>> "TASKSET_PRINTF_MASK"\n",
>> - pid, current_new, from_mask(mask,
>> mask_size_in_bytes));
>> + if (opts & OPT_p) {
>> +#if ENABLE_FEATURE_TASKSET_CPULIST
>> + if (opts & OPT_c) {
>> + printf("pid %d's %s affinity list: ", pid,
>> current_new);
>> + print_cpulist(mask, mask_size_in_bytes * 8);
>> + } else
>> +#endif
>> + printf("pid %d's %s affinity mask: "
>> TASKSET_PRINTF_MASK"\n",
>> + pid, current_new, from_mask(mask,
>> mask_size_in_bytes));
>> +
>> if (*argv == NULL) {
>> /* Either it was just "-p <pid>",
>> * or it was "-p <aff> <pid>" and we came here
>> @@ -158,55 +290,67 @@ int taskset_main(int argc UNUSED_PARAM, char
>> **argv)
>> }
>> memset(mask, 0, mask_size_in_bytes);
>>
>> - /* Affinity was specified, translate it into mask */
>> - /* it is always in hex, skip "0x" if it exists */
>> - if (aff[0] == '0' && (aff[1]|0x20) == 'x')
>> - aff += 2;
>> -
>> - if (!ENABLE_FEATURE_TASKSET_FANCY) {
>> - mask[0] = xstrtoul(aff, 16);
>> +#if ENABLE_FEATURE_TASKSET_CPULIST
>> + if (opts & OPT_c) {
>> + /* Cpulist */
>> + if (parse_cpulist(mask, mask_size_in_bytes * 8, aff) < 0)
>> + bb_error_msg_and_die("bad affinity '%s'", aff);
>> } else {
>> - unsigned i;
>> - char *last_char;
>> -
>> - i = 0; /* bit pos in mask[] */
>> -
>> - /* aff is ASCII hex string, accept very long masks in this
>> form.
>> - * Process hex string AABBCCDD... to ulong mask[]
>> - * from the rightmost nibble, which is least-significant.
>> - * Bits not fitting into mask[] are ignored: (example:
>> 1234
>> - * in 12340000000000000000000000000000000000000ff)
>> - */
>> - last_char = strchrnul(aff, '\0');
>> - while (last_char > aff) {
>> - char c;
>> - ul val;
>> -
>> - last_char--;
>> - c = *last_char;
>> - if (isdigit(c))
>> - val = c - '0';
>> - else if ((c|0x20) >= 'a' && (c|0x20) <= 'f')
>> - val = (c|0x20) - ('a' - 10);
>> - else
>> - bb_error_msg_and_die("bad affinity '%s'",
>> aff);
>> -
>> - if (i < mask_size_in_bytes * 8) {
>> - mask[i / BITS_UL] |= val << (i &
>> MASK_UL);
>> - //bb_error_msg("bit %d set", i);
>> - }
>> - /* else:
>> - * We can error out here, but we don't.
>> - * For one, kernel itself ignores bits in mask[]
>> - * which do not map to any CPUs:
>> - * if mask[] has one 32-bit long element,
>> - * but you have only 8 CPUs, all bits beyond first
>> 8
>> - * are ignored, silently.
>> - * No point in making bits past 31th to be
>> errors.
>> +#endif
>> + /* Bitmask */
>> +
>> + /* Affinity was specified, translate it into mask */
>> + /* it is always in hex, skip "0x" if it exists */
>> + if (aff[0] == '0' && (aff[1]|0x20) == 'x')
>> + aff += 2;
>> +
>> + if (!ENABLE_FEATURE_TASKSET_FANCY) {
>> + mask[0] = xstrtoul(aff, 16);
>> + } else {
>> + unsigned i;
>> + char *last_char;
>> +
>> + i = 0; /* bit pos in mask[] */
>> +
>> + /* aff is ASCII hex string, accept very long masks
>> in this form.
>> + * Process hex string AABBCCDD... to ulong mask[]
>> + * from the rightmost nibble, which is
>> least-significant.
>> + * Bits not fitting into mask[] are ignored:
>> (example: 1234
>> + * in
>> 12340000000000000000000000000000000000000ff)
>> */
>> - i += 4;
>> + last_char = strchrnul(aff, '\0');
>> + while (last_char > aff) {
>> + char c;
>> + ul val;
>> +
>> + last_char--;
>> + c = *last_char;
>> + if (isdigit(c))
>> + val = c - '0';
>> + else if ((c|0x20) >= 'a' && (c|0x20) <=
>> 'f')
>> + val = (c|0x20) - ('a' - 10);
>> + else
>> + bb_error_msg_and_die("bad affinity
>> '%s'", aff);
>> +
>> + if (i < mask_size_in_bytes * 8) {
>> + mask[i / BITS_UL] |= val << (i &
>> MASK_UL);
>> + //bb_error_msg("bit %d set", i);
>> + }
>> + /* else:
>> + * We can error out here, but we don't.
>> + * For one, kernel itself ignores bits in
>> mask[]
>> + * which do not map to any CPUs:
>> + * if mask[] has one 32-bit long element,
>> + * but you have only 8 CPUs, all bits
>> beyond first 8
>> + * are ignored, silently.
>> + * No point in making bits past 31th to be
>> errors.
>> + */
>> + i += 4;
>> + }
>> }
>> +#if ENABLE_FEATURE_TASKSET_CPULIST
>> }
>> +#endif
>>
>> /* Set pid's or our own (pid==0) affinity */
>> if (sched_setaffinity(pid, mask_size_in_bytes, (void*)mask))
>> _______________________________________________
>> busybox mailing list
>> busybox@busybox.net
>> http://lists.busybox.net/mailman/listinfo/busybox
>
_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic