c3568ea376
Spawning the ctrl threads on anything that is not part of the eal coremask is not that polite to the rest of the system, especially when you took good care to pin your processes on cpu resources with tools like taskset (linux) / cpuset (freebsd). Rather than introduce yet another eal options to control on which cpu those ctrl threads are created, let's take the startup cpu affinity as a reference and remove the eal coremask from it. If no cpu is left, then we default to the master core. The cpuset is computed once at init before the original cpu affinity is lost. Introduced a RTE_CPU_AND macro to abstract the differences between linux and freebsd respective macros. Examples in a 4 cores FreeBSD vm: $ ./build/app/testpmd -l 2,3 --no-huge --no-pci -m 512 \ -- -i --total-num-mbufs=2048 $ procstat -S 1057 PID TID COMM TDNAME CPU CSID CPU MASK 1057 100131 testpmd - 2 1 2 1057 100140 testpmd eal-intr-thread 1 1 0-1 1057 100141 testpmd rte_mp_handle 1 1 0-1 1057 100142 testpmd lcore-slave-3 3 1 3 $ cpuset -l 1,2,3 ./build/app/testpmd -l 2,3 --no-huge --no-pci -m 512 \ -- -i --total-num-mbufs=2048 $ procstat -S 1061 PID TID COMM TDNAME CPU CSID CPU MASK 1061 100131 testpmd - 2 2 2 1061 100144 testpmd eal-intr-thread 1 2 1 1061 100145 testpmd rte_mp_handle 1 2 1 1061 100147 testpmd lcore-slave-3 3 2 3 $ cpuset -l 2,3 ./build/app/testpmd -l 2,3 --no-huge --no-pci -m 512 \ -- -i --total-num-mbufs=2048 $ procstat -S 1065 PID TID COMM TDNAME CPU CSID CPU MASK 1065 100131 testpmd - 2 2 2 1065 100148 testpmd eal-intr-thread 2 2 2 1065 100149 testpmd rte_mp_handle 2 2 2 1065 100150 testpmd lcore-slave-3 3 2 3 Fixes: d651ee4919cd ("eal: set affinity for control threads") Cc: stable@dpdk.org Signed-off-by: David Marchand <david.marchand@redhat.com> Reviewed-by: Anatoly Burakov <anatoly.burakov@intel.com> Reviewed-by: Olivier Matz <olivier.matz@6wind.com>
220 lines
4.3 KiB
C
220 lines
4.3 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright(c) 2010-2014 Intel Corporation
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <unistd.h>
|
|
#include <pthread.h>
|
|
#include <signal.h>
|
|
#include <sched.h>
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
|
|
#include <rte_lcore.h>
|
|
#include <rte_memory.h>
|
|
#include <rte_log.h>
|
|
|
|
#include "eal_internal_cfg.h"
|
|
#include "eal_private.h"
|
|
#include "eal_thread.h"
|
|
|
|
RTE_DECLARE_PER_LCORE(unsigned , _socket_id);
|
|
|
|
unsigned rte_socket_id(void)
|
|
{
|
|
return RTE_PER_LCORE(_socket_id);
|
|
}
|
|
|
|
int
|
|
rte_lcore_has_role(unsigned int lcore_id, enum rte_lcore_role_t role)
|
|
{
|
|
struct rte_config *cfg = rte_eal_get_configuration();
|
|
|
|
if (lcore_id >= RTE_MAX_LCORE)
|
|
return -EINVAL;
|
|
|
|
return cfg->lcore_role[lcore_id] == role;
|
|
}
|
|
|
|
int eal_cpuset_socket_id(rte_cpuset_t *cpusetp)
|
|
{
|
|
unsigned cpu = 0;
|
|
int socket_id = SOCKET_ID_ANY;
|
|
int sid;
|
|
|
|
if (cpusetp == NULL)
|
|
return SOCKET_ID_ANY;
|
|
|
|
do {
|
|
if (!CPU_ISSET(cpu, cpusetp))
|
|
continue;
|
|
|
|
if (socket_id == SOCKET_ID_ANY)
|
|
socket_id = eal_cpu_socket_id(cpu);
|
|
|
|
sid = eal_cpu_socket_id(cpu);
|
|
if (socket_id != sid) {
|
|
socket_id = SOCKET_ID_ANY;
|
|
break;
|
|
}
|
|
|
|
} while (++cpu < RTE_MAX_LCORE);
|
|
|
|
return socket_id;
|
|
}
|
|
|
|
int
|
|
rte_thread_set_affinity(rte_cpuset_t *cpusetp)
|
|
{
|
|
int s;
|
|
unsigned lcore_id;
|
|
pthread_t tid;
|
|
|
|
tid = pthread_self();
|
|
|
|
s = pthread_setaffinity_np(tid, sizeof(rte_cpuset_t), cpusetp);
|
|
if (s != 0) {
|
|
RTE_LOG(ERR, EAL, "pthread_setaffinity_np failed\n");
|
|
return -1;
|
|
}
|
|
|
|
/* store socket_id in TLS for quick access */
|
|
RTE_PER_LCORE(_socket_id) =
|
|
eal_cpuset_socket_id(cpusetp);
|
|
|
|
/* store cpuset in TLS for quick access */
|
|
memmove(&RTE_PER_LCORE(_cpuset), cpusetp,
|
|
sizeof(rte_cpuset_t));
|
|
|
|
lcore_id = rte_lcore_id();
|
|
if (lcore_id != (unsigned)LCORE_ID_ANY) {
|
|
/* EAL thread will update lcore_config */
|
|
lcore_config[lcore_id].socket_id = RTE_PER_LCORE(_socket_id);
|
|
memmove(&lcore_config[lcore_id].cpuset, cpusetp,
|
|
sizeof(rte_cpuset_t));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
rte_thread_get_affinity(rte_cpuset_t *cpusetp)
|
|
{
|
|
assert(cpusetp);
|
|
memmove(cpusetp, &RTE_PER_LCORE(_cpuset),
|
|
sizeof(rte_cpuset_t));
|
|
}
|
|
|
|
int
|
|
eal_thread_dump_affinity(char *str, unsigned size)
|
|
{
|
|
rte_cpuset_t cpuset;
|
|
unsigned cpu;
|
|
int ret;
|
|
unsigned int out = 0;
|
|
|
|
rte_thread_get_affinity(&cpuset);
|
|
|
|
for (cpu = 0; cpu < RTE_MAX_LCORE; cpu++) {
|
|
if (!CPU_ISSET(cpu, &cpuset))
|
|
continue;
|
|
|
|
ret = snprintf(str + out,
|
|
size - out, "%u,", cpu);
|
|
if (ret < 0 || (unsigned)ret >= size - out) {
|
|
/* string will be truncated */
|
|
ret = -1;
|
|
goto exit;
|
|
}
|
|
|
|
out += ret;
|
|
}
|
|
|
|
ret = 0;
|
|
exit:
|
|
/* remove the last separator */
|
|
if (out > 0)
|
|
str[out - 1] = '\0';
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
struct rte_thread_ctrl_params {
|
|
void *(*start_routine)(void *);
|
|
void *arg;
|
|
pthread_barrier_t configured;
|
|
};
|
|
|
|
static void *rte_thread_init(void *arg)
|
|
{
|
|
int ret;
|
|
struct rte_thread_ctrl_params *params = arg;
|
|
void *(*start_routine)(void *) = params->start_routine;
|
|
void *routine_arg = params->arg;
|
|
|
|
ret = pthread_barrier_wait(¶ms->configured);
|
|
if (ret == PTHREAD_BARRIER_SERIAL_THREAD) {
|
|
pthread_barrier_destroy(¶ms->configured);
|
|
free(params);
|
|
}
|
|
|
|
return start_routine(routine_arg);
|
|
}
|
|
|
|
__rte_experimental int
|
|
rte_ctrl_thread_create(pthread_t *thread, const char *name,
|
|
const pthread_attr_t *attr,
|
|
void *(*start_routine)(void *), void *arg)
|
|
{
|
|
rte_cpuset_t *cpuset = &internal_config.ctrl_cpuset;
|
|
struct rte_thread_ctrl_params *params;
|
|
int ret;
|
|
|
|
params = malloc(sizeof(*params));
|
|
if (!params)
|
|
return -ENOMEM;
|
|
|
|
params->start_routine = start_routine;
|
|
params->arg = arg;
|
|
|
|
pthread_barrier_init(¶ms->configured, NULL, 2);
|
|
|
|
ret = pthread_create(thread, attr, rte_thread_init, (void *)params);
|
|
if (ret != 0) {
|
|
free(params);
|
|
return -ret;
|
|
}
|
|
|
|
if (name != NULL) {
|
|
ret = rte_thread_setname(*thread, name);
|
|
if (ret < 0)
|
|
RTE_LOG(DEBUG, EAL,
|
|
"Cannot set name for ctrl thread\n");
|
|
}
|
|
|
|
ret = pthread_setaffinity_np(*thread, sizeof(*cpuset), cpuset);
|
|
if (ret)
|
|
goto fail;
|
|
|
|
ret = pthread_barrier_wait(¶ms->configured);
|
|
if (ret == PTHREAD_BARRIER_SERIAL_THREAD) {
|
|
pthread_barrier_destroy(¶ms->configured);
|
|
free(params);
|
|
}
|
|
|
|
return 0;
|
|
|
|
fail:
|
|
if (PTHREAD_BARRIER_SERIAL_THREAD ==
|
|
pthread_barrier_wait(¶ms->configured)) {
|
|
pthread_barrier_destroy(¶ms->configured);
|
|
free(params);
|
|
}
|
|
pthread_cancel(*thread);
|
|
pthread_join(*thread, NULL);
|
|
return -ret;
|
|
}
|