Applied a modified version, please try current git.
On Wed, Oct 30, 2019 at 6:55 PM Fryderyk Wrobel <[email protected]> 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 > [email protected] > http://lists.busybox.net/mailman/listinfo/busybox _______________________________________________ busybox mailing list [email protected] http://lists.busybox.net/mailman/listinfo/busybox
