workers 2
+relative
+^^^^^^^^^
+
+Apply thread pinning configuration with respect to the available logical cores
+in the current control group CPU set.
+By default, VPP applies the thread pinning configuration with respect to the
+available logical cores on host (e.g. '/sys/devices/system/cpu/online'). With
+the 'relative' keyword, the thread pinning configuration is applied with respect
+to the available logical cores (obtained with sched_getaffinity).
+
+.. code-block:: console
+
+ relative
+
scheduler-policy other | batch | idle | fifo | rr
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
and it will run threads on them
- if “corelist-workers A,B1-Bn,C1-Cn” is defined vpp will automatically
assign those CPU cores to worker threads
+- if "relative" is defined, vpp will consider cores it has affinity
+ (using sched_getaffinity) rather than all cores available on the
+ host machine. This is useful if running in a containerized environment which
+ is only allowed to use a subset of the host's CPUs.
User can see active placement of cores by using the VPP debug CLI
command show threads:
workers 3
}
+Relative Placement
+~~~~~~~~~~~~~~~~~~
+
+Relative placement can be used in addition to manual or auto placement. It takes
+into consideration that the VPP might be allowed to run on a limited subset of
+logical cores on the host machine (e.g. running in a container), and automatically
+remaps the user requested pinning configuration to the logical cores available to VPP
+(checked using sched_getaffinity).
+If a VPP instance runs with CPU set 20,25,26,27 and relative mode is enabled, a
+manual placement of main thread on core 0 and workers on cores 2,3 will result
+in placement of main thread on core 20 and workers on cores 26,27.
+
+.. code-block:: console
+
+ cpu {
+ main-core 0
+ corelist-workers 2-3
+ relative
+ }
+
Buffer Memory Allocation
~~~~~~~~~~~~~~~~~~~~~~~~
Geneve
gerrit
Gerrit
+getaffinity
gethostbyname
gettingsources
gettingstarted
scapy
Scapy
SCHED_RR
+sched
sclass
scooby
screenshot
u32 first_index = 1;
u32 i;
uword *avail_cpu;
+ uword n_cpus;
u32 stats_num_worker_threads_dir_index;
stats_num_worker_threads_dir_index =
ASSERT (stats_num_worker_threads_dir_index != ~0);
/* get bitmaps of active cpu cores and sockets */
- tm->cpu_core_bitmap = os_get_online_cpu_core_bitmap ();
tm->cpu_socket_bitmap = os_get_online_cpu_node_bitmap ();
+ if (!tm->cpu_translate)
+ tm->cpu_core_bitmap = os_get_online_cpu_core_bitmap ();
+ else
+ {
+ /* get bitmap of cpu core affinity */
+ if ((tm->cpu_core_bitmap = os_get_cpu_affinity_bitmap ()) == 0)
+ return clib_error_return (0, "could not fetch cpu affinity bmp");
+ }
avail_cpu = clib_bitmap_dup (tm->cpu_core_bitmap);
/* skip cores */
+ n_cpus = clib_bitmap_count_set_bits (avail_cpu);
+ if (tm->skip_cores >= n_cpus)
+ return clib_error_return (
+ 0, "skip-core value greater or equal to available cpus");
+
for (i = 0; i < tm->skip_cores; i++)
{
uword c = clib_bitmap_first_set (avail_cpu);
if (tm->main_lcore != ~0)
{
if (clib_bitmap_get (avail_cpu, tm->main_lcore) == 0)
- return clib_error_return (0, "cpu %u is not available to be used"
- " for the main thread", tm->main_lcore);
+ {
+ if (tm->cpu_translate)
+ return clib_error_return (
+ 0,
+ "cpu %u (relative cpu %u) is not available to be used"
+ " for the main thread in relative mode",
+ tm->main_lcore,
+ os_translate_cpu_from_affinity_bitmap (tm->main_lcore));
+ else
+ return clib_error_return (0,
+ "cpu %u is not available to be used"
+ " for the main thread",
+ tm->main_lcore);
+ }
avail_cpu = clib_bitmap_set (avail_cpu, tm->main_lcore, 0);
}
uword c;
clib_bitmap_foreach (c, tr->coremask) {
if (clib_bitmap_get(avail_cpu, c) == 0)
- return clib_error_return (0, "cpu %u is not available to be used"
- " for the '%s' thread",c, tr->name);
-
- avail_cpu = clib_bitmap_set(avail_cpu, c, 0);
- }
+ {
+ if (tm->cpu_translate)
+ return clib_error_return (
+ 0,
+ "cpu %u (relative cpu %u) is not available to be used"
+ " for the '%s' thread in relative mode",
+ c, os_translate_cpu_from_affinity_bitmap (c), tr->name);
+ else
+ return clib_error_return (
+ 0,
+ "cpu %u is not available to be used"
+ " for the '%s' thread",
+ c, tr->name);
+ }
+
+ avail_cpu = clib_bitmap_set (avail_cpu, c, 0);
+ }
}
else
{
uword c = clib_bitmap_first_set (avail_cpu);
/* Use CPU 0 as a last resort */
- if (c == ~0 && avail_c0)
+ if (c == ~0 && avail_c0 && !tm->cpu_translate)
{
c = 0;
avail_c0 = 0;
return clib_error_return (0,
"no available cpus to be used for"
" the '%s' thread #%u",
- tr->name, tr->count);
+ tr->name, j);
avail_cpu = clib_bitmap_set (avail_cpu, 0, avail_c0);
avail_cpu = clib_bitmap_set (avail_cpu, c, 0);
;
else if (unformat (input, "skip-cores %u", &tm->skip_cores))
;
+ else if (unformat (input, "relative"))
+ tm->cpu_translate = 1;
else if (unformat (input, "numa-heap-size %U",
unformat_memory_size, &tm->numa_heap_size))
;
tr = tr->next;
}
+ /* for relative mode, update requested main-core and corelists */
+ if (tm->cpu_translate)
+ {
+
+ if (tm->main_lcore == ~0)
+ clib_error ("main-core must be specified in relative mode");
+ int cpu_translate_main_core =
+ os_translate_cpu_to_affinity_bitmap (tm->main_lcore);
+ if (cpu_translate_main_core == -1)
+ clib_error ("cpu %u is not available to be used"
+ " for the main thread in relative mode",
+ tm->main_lcore);
+ tm->main_lcore = cpu_translate_main_core;
+
+ tr = tm->next;
+ uword *translated_cpu_bmp;
+ while (tr && tr->coremask)
+ {
+ translated_cpu_bmp =
+ os_translate_cpu_bmp_to_affinity_bitmap (tr->coremask);
+
+ if (!translated_cpu_bmp)
+ clib_error ("could not translate corelist associated to %s",
+ tr->name);
+ clib_bitmap_free (tr->coremask);
+ tr->coremask = translated_cpu_bmp;
+ tr = tr->next;
+ }
+ }
+
return 0;
}
int use_pthreads;
+ /* Translate requested cpu configuration to vpp affinity mask */
+ int cpu_translate;
+
/* Number of vlib_main / vnet_main clones */
u32 n_vlib_mains;
*/
#define _GNU_SOURCE
+#include <vppinfra/bitmap.h>
+#include <vppinfra/unix.h>
#include <vppinfra/format.h>
#include <vlib/vlib.h>
const vlib_thread_main_t *tm = vlib_get_thread_main ();
vlib_worker_thread_t *w;
int i;
+ u8 *line = NULL;
- vlib_cli_output (vm, "%-7s%-20s%-12s%-8s%-25s%-7s%-7s%-7s%-10s",
- "ID", "Name", "Type", "LWP", "Sched Policy (Priority)",
- "lcore", "Core", "Socket", "State");
+ line = format (line, "%-7s%-20s%-12s%-8s%-25s%-7s%-7s%-7s%-10s", "ID",
+ "Name", "Type", "LWP", "Sched Policy (Priority)", "lcore",
+ "Core", "Socket", "State");
+ if (tm->cpu_translate)
+ line = format (line, "%-15s", "Relative Core");
+ vlib_cli_output (vm, "%v", line);
+ vec_free (line);
#if !defined(__powerpc64__)
for (i = 0; i < vec_len (vlib_worker_threads); i++)
{
w = vlib_worker_threads + i;
- u8 *line = NULL;
line = format (line, "%-7d%-20s%-12s%-8d",
i,
{
int core_id = w->core_id;
int numa_id = w->numa_id;
- line = format (line, "%-7u%-7u%-7u%", cpu_id, core_id, numa_id);
+ line = format (line, "%-7u%-7u%-17u%", cpu_id, core_id, numa_id);
+ if (tm->cpu_translate)
+ {
+ int cpu_translate_core_id =
+ os_translate_cpu_from_affinity_bitmap (cpu_id);
+ line = format (line, "%-7u", cpu_translate_core_id);
+ }
}
else
{
unformat_input_t input, sub_input;
u8 *s = 0, *v = 0;
int main_core = ~0;
+ int cpu_translate = 0;
cpu_set_t cpuset;
void *main_heap;
unix_main.flags |= UNIX_FLAG_INTERACTIVE;
else if (!strncmp (argv[i], "nosyslog", 8))
unix_main.flags |= UNIX_FLAG_NOSYSLOG;
+ else if (!strncmp (argv[i], "relative", 8))
+ cpu_translate = 1;
}
defaulted:
unformat_free (&input);
+ int translate_main_core = os_translate_cpu_to_affinity_bitmap (main_core);
+
+ if (cpu_translate && main_core != ~0)
+ {
+ if (translate_main_core == -1)
+ clib_error ("cpu %u is not available to be used"
+ " for the main thread in relative mode",
+ main_core);
+ main_core = translate_main_core;
+ }
+
/* if main thread affinity is unspecified, set to current running cpu */
if (main_core == ~0)
main_core = sched_getcpu ();
__clib_export __thread uword __os_thread_index = 0;
__clib_export __thread uword __os_numa_index = 0;
-
-__clib_export clib_bitmap_t *os_get_cpu_affinity_bitmap (int pid);
+__clib_export cpu_set_t __os_affinity_cpu_set;
+__clib_export clib_bitmap_t *os_get_cpu_affinity_bitmap ();
clib_error_t *
clib_file_n_bytes (char *file, uword * result)
}
__clib_export clib_bitmap_t *
-os_get_cpu_affinity_bitmap (int pid)
+os_get_cpu_affinity_bitmap ()
{
#if __linux
- int index, ret;
- cpu_set_t cpuset;
+ int cpu;
uword *affinity_cpus;
- clib_bitmap_alloc (affinity_cpus, sizeof (cpu_set_t));
+ clib_bitmap_alloc (affinity_cpus, __CPU_SETSIZE);
clib_bitmap_zero (affinity_cpus);
- CPU_ZERO_S (sizeof (cpu_set_t), &cpuset);
-
- ret = sched_getaffinity (0, sizeof (cpu_set_t), &cpuset);
-
- if (ret < 0)
+ /* set__os_affinity_cpu_set once on first call to
+ * os_get_cpu_affinity_bitmap() */
+ if (__CPU_COUNT_S (sizeof (cpu_set_t), &__os_affinity_cpu_set) == 0)
{
- clib_bitmap_free (affinity_cpus);
- return 0;
+ int ret;
+ ret = sched_getaffinity (0, sizeof (cpu_set_t), &__os_affinity_cpu_set);
+ if (ret < 0)
+ {
+ clib_bitmap_free (affinity_cpus);
+ return NULL;
+ }
}
- for (index = 0; index < sizeof (cpu_set_t); index++)
- if (CPU_ISSET_S (index, sizeof (cpu_set_t), &cpuset))
- clib_bitmap_set (affinity_cpus, index, 1);
+ for (cpu = 0; cpu < __CPU_SETSIZE; cpu++)
+ if (__CPU_ISSET_S (cpu, sizeof (cpu_set_t), &__os_affinity_cpu_set))
+ clib_bitmap_set (affinity_cpus, cpu, 1);
return affinity_cpus;
#elif defined(__FreeBSD__)
cpuset_t mask;
#endif
}
+__clib_export int
+os_translate_cpu_to_affinity_bitmap (int cpu)
+{
+ uword *affinity_bmp = os_get_cpu_affinity_bitmap ();
+ int cpu_it = 0;
+ int cpu_translate_it = 0;
+
+ if (!affinity_bmp)
+ return -1;
+
+ if (cpu == ~0)
+ goto err;
+
+ clib_bitmap_foreach (cpu_it, affinity_bmp)
+ {
+
+ if (cpu == cpu_translate_it)
+ {
+ clib_bitmap_free (affinity_bmp);
+ return cpu_it;
+ }
+
+ cpu_translate_it += 1;
+ }
+
+err:
+ clib_bitmap_free (affinity_bmp);
+ return -1;
+}
+
+__clib_export int
+os_translate_cpu_from_affinity_bitmap (int cpu_translated)
+{
+ uword *affinity_bmp = os_get_cpu_affinity_bitmap ();
+ int cpu_it = 0;
+ int cpu_translate_it = 0;
+
+ if (!affinity_bmp)
+ return -1;
+
+ if (cpu_translated == ~0)
+ goto err;
+
+ clib_bitmap_foreach (cpu_it, affinity_bmp)
+ {
+
+ if (cpu_translated == cpu_it)
+ {
+ clib_bitmap_free (affinity_bmp);
+ return cpu_translate_it;
+ }
+
+ cpu_translate_it += 1;
+ }
+
+err:
+ clib_bitmap_free (affinity_bmp);
+ return -1;
+}
+
+__clib_export clib_bitmap_t *
+os_translate_cpu_bmp_to_affinity_bitmap (clib_bitmap_t *cpu_bmp)
+{
+ uword *affinity_bmp = os_get_cpu_affinity_bitmap ();
+
+ if (!affinity_bmp)
+ return NULL;
+
+ u32 cpu_count_relative = clib_bitmap_count_set_bits (affinity_bmp);
+ u32 cpu_max_corelist = clib_bitmap_last_set (cpu_bmp);
+
+ if (cpu_count_relative <= cpu_max_corelist)
+ return NULL;
+
+ uword *translated_cpulist;
+ clib_bitmap_alloc (translated_cpulist, __CPU_SETSIZE);
+ clib_bitmap_zero (translated_cpulist);
+
+ uword cpu_it;
+ uword cpu_translate_it = 0;
+
+ clib_bitmap_foreach (cpu_it, affinity_bmp)
+ {
+
+ if (clib_bitmap_get (cpu_bmp, cpu_translate_it))
+ clib_bitmap_set (translated_cpulist, cpu_it, 1);
+
+ cpu_translate_it++;
+ }
+
+ vec_free (affinity_bmp);
+ return translated_cpulist;
+}
+
__clib_export clib_bitmap_t *
os_get_online_cpu_node_bitmap ()
{
/* Retrieve bitmap of online cpu cures */
clib_bitmap_t *os_get_online_cpu_core_bitmap ();
+/* Retrieve bitmap of cpu affinity */
+clib_bitmap_t *os_get_cpu_affinity_bitmap ();
+
+/* Translate cpu index in cpu affinity bitmap */
+int os_translate_cpu_to_affinity_bitmap (int cpu);
+
+/* Retrieve cpu index after translation in cpu affinity bitmap */
+int os_translate_cpu_from_affinity_bitmap (int cpu_translated);
+
+/* Translate cpu bitmap based on cpu affinity bitmap */
+clib_bitmap_t *
+os_translate_cpu_bmp_to_affinity_bitmap (clib_bitmap_t *cpu_bmp);
+
/* Retrieve bitmap of online cpu nodes (sockets) */
clib_bitmap_t *os_get_online_cpu_node_bitmap ();