From 09774813a4678b7e89c13fda275e18ae6f62b1c1 Mon Sep 17 00:00:00 2001 From: Stefan Reif Date: Mon, 4 Dec 2017 11:23:56 +0100 Subject: [PATCH] Allow run-time configuration of core pinning Use the environment variable "PRRT_CORES" to restrict a PRRT socket to specific cpu cores. --- prrt/util/common.c | 8 +++ prrt/util/cpulist.h | 148 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 prrt/util/cpulist.h diff --git a/prrt/util/common.c b/prrt/util/common.c index 780b2f8f..37b2397e 100644 --- a/prrt/util/common.c +++ b/prrt/util/common.c @@ -1,4 +1,5 @@ #include +#include #include #include "common.h" @@ -28,10 +29,17 @@ void print_gf(const gf *start, const int len) { printf("\n"); } +#include "cpulist.h" int pin_thread_to_core(pthread_attr_t *ap, int core) { + char *cpulist_conf = getenv("PRRT_CORES"); + if (cpulist_conf) { + uint32_t cpulist = cpulist_parse(cpulist_conf); + core = cpulist_get_cpu(cpulist, core); + } cpu_set_t cpuset; CPU_ZERO(&cpuset); CPU_SET(core, &cpuset); return pthread_attr_setaffinity_np(ap, sizeof(cpu_set_t), &cpuset); } + diff --git a/prrt/util/cpulist.h b/prrt/util/cpulist.h new file mode 100644 index 00000000..32ee920c --- /dev/null +++ b/prrt/util/cpulist.h @@ -0,0 +1,148 @@ +#ifndef PRRT_CPULIST_H +#define PRRT_CPULIST_H + +#include +#include +#include +#include + +#define CPULIST_ERR ((uint32_t) 0) + +#ifdef __GNUC__ +# define cpulist__inline inline __attribute__((__always_inline__,__unused__)) +#else +# define cpulist__inline inline +#endif + +/** + * Add a cpu number to a cpu list + * + * \param cpulist the cpu list + * \param num the cpu number + * \returns a new cpu list that contains all cpus from the given cpu list, plus + * the new number. If the old cpu list already contains the given cpu number, + * it is returned unmodified. + */ +static cpulist__inline +uint32_t cpulist_add_cpu(uint32_t cpulist, unsigned int bit) { + if (bit >= 32) + return cpulist; + uint32_t one = 1; + return cpulist | (one << bit); +} + +/** + * Check if a cpu number is included in a cpu list + * + * \param cpulist the cpu list + * \param num a cpu number + * \returns \c true if the cpu list included the given cpu number, \c false otherwise + */ +static cpulist__inline +bool cpulist_has_cpu(uint32_t cpulist, unsigned int num) { + if (num >= 32) + return false; + uint32_t one = 1; + return !!(cpulist & (one << num)); +} + +/** + * + * The purpose of this function is to assign arbitrary cpu numbers to cpu + * numbers allowed by the given cpu list. This is a very simple way of work + * distribution. + * + * \param cpulist the cpu list + * \param num an arbitrary cpu number that is mapped to a cpu number allowed by the given cpu list + * \returns a cpu number that is included in the cpu list, if possible + * \returns UINT_MAX if the cpu list is empty + */ +static cpulist__inline +unsigned int cpulist_get_cpu(uint32_t cpulist, unsigned int num) { + if (!cpulist) + return 0; + // TODO: find a better load distribution algorithm + unsigned int bit = UINT_MAX; + bool has = 0; + do { + num -= has; + bit = (bit + 1) & 31; + has = cpulist_has_cpu(cpulist, bit); + } while (num || !has); + return bit; +} + +/** + * Remove all large cpu numbers from a cpu list + * + * This function removes all large cpu numbers from a cpu list. The given limit + * is removed as well. Only cpus lower than num remain in the cpu list. + * + * The purpose of this function is to limit a cpu list to cpu numbers that are + * actually available in the system. + * + * \param cpulist the cpu list + * \param num the cpu limit + * \returns the new cpu list with large numbers removed + */ +static cpulist__inline +uint32_t cpulist_cut(uint32_t cpulist, unsigned int num) { + uint32_t one = 1; + uint32_t all = (one << num) - 1; + return cpulist & all; +} + +/** + * Parse a cpu list + * + * This function takes a string that describes a cpu list in an intuitive + * format and converts it to a machine-readable cpu list. + * + * Example: "1-3,5" ==> [ 1, 2, 3, 5 ] + * + * Syntax: + * cpulist ::= | ',' # comma-separated list of ranges + * range ::= | '-' # single number or actual range + * num ::= | # at least one digit + * digit ::= '0' .. '9' + */ +static cpulist__inline +uint32_t cpulist_parse(const char *str) +{ + uint32_t result = 0; + char *pos = (char *) str; + while (*pos) { + char *end; + long from = strtol(pos, &end, 10); + long to; + switch(*end) { + case '\0': + case ',': + to = from; + break; + case '-': + pos = end + 1; + to = strtol(pos, &end, 10); + break; + default: + return CPULIST_ERR; + } + pos = end; + + for (long l = from; l <= to; l++) + result = cpulist_add_cpu(result, (int) l); + + switch (*pos) { + case '\0': + return result; + case ',': + pos++; + break; + default: + return CPULIST_ERR; + } + } + return result; +} + +#endif /* PRRT_CPULIST_H */ -- GitLab