Commit 09774813 authored by Stefan Reif's avatar Stefan Reif Committed by Andreas Schmidt
Browse files

Allow run-time configuration of core pinning

Use the environment variable "PRRT_CORES" to restrict a PRRT socket to
specific cpu cores.
parent f37cb1d5
Loading
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>

#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);
}

prrt/util/cpulist.h

0 → 100644
+148 −0
Original line number Diff line number Diff line
#ifndef PRRT_CPULIST_H
#define PRRT_CPULIST_H

#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <limits.h>

#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 ::= <range> | <range> ',' <range> # comma-separated list of ranges
 *  range   ::= <num>   | <num> '-' <num>     # single number or actual range
 *  num     ::= <digit> | <num> <digit>       # 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 */