vppinfra: numa vector placement support
Type: feature Signed-off-by: Dave Barach <dave@barachs.net> Change-Id: I7e7d95a089dd849c1f01ecea84529d8dbf239f21
This commit is contained in:

committed by
Florin Coras

parent
86e8bce44f
commit
a690fdbfe1
@@ -133,8 +133,10 @@ http_static_server_session_alloc (u32 thread_index)
|
|||||||
{
|
{
|
||||||
http_static_server_main_t *hsm = &http_static_server_main;
|
http_static_server_main_t *hsm = &http_static_server_main;
|
||||||
http_session_t *hs;
|
http_session_t *hs;
|
||||||
pool_get (hsm->sessions[thread_index], hs);
|
pool_get_aligned_zero_numa (hsm->sessions[thread_index], hs,
|
||||||
memset (hs, 0, sizeof (*hs));
|
0 /* not aligned */ ,
|
||||||
|
1 /* zero */ ,
|
||||||
|
os_get_numa_index ());
|
||||||
hs->session_index = hs - hsm->sessions[thread_index];
|
hs->session_index = hs - hsm->sessions[thread_index];
|
||||||
hs->thread_index = thread_index;
|
hs->thread_index = thread_index;
|
||||||
hs->timer_handle = ~0;
|
hs->timer_handle = ~0;
|
||||||
|
@@ -733,9 +733,10 @@ show_memory_usage (vlib_main_t * vm,
|
|||||||
unformat_input_t * input, vlib_cli_command_t * cmd)
|
unformat_input_t * input, vlib_cli_command_t * cmd)
|
||||||
{
|
{
|
||||||
int verbose __attribute__ ((unused)) = 0;
|
int verbose __attribute__ ((unused)) = 0;
|
||||||
int api_segment = 0, stats_segment = 0, main_heap = 0;
|
int api_segment = 0, stats_segment = 0, main_heap = 0, numa_heaps = 0;
|
||||||
clib_error_t *error;
|
clib_error_t *error;
|
||||||
u32 index = 0;
|
u32 index = 0;
|
||||||
|
int i;
|
||||||
uword clib_mem_trace_enable_disable (uword enable);
|
uword clib_mem_trace_enable_disable (uword enable);
|
||||||
uword was_enabled;
|
uword was_enabled;
|
||||||
|
|
||||||
@@ -750,6 +751,8 @@ show_memory_usage (vlib_main_t * vm,
|
|||||||
stats_segment = 1;
|
stats_segment = 1;
|
||||||
else if (unformat (input, "main-heap"))
|
else if (unformat (input, "main-heap"))
|
||||||
main_heap = 1;
|
main_heap = 1;
|
||||||
|
else if (unformat (input, "numa-heaps"))
|
||||||
|
numa_heaps = 1;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
error = clib_error_return (0, "unknown input `%U'",
|
error = clib_error_return (0, "unknown input `%U'",
|
||||||
@@ -758,9 +761,9 @@ show_memory_usage (vlib_main_t * vm,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((api_segment + stats_segment + main_heap) == 0)
|
if ((api_segment + stats_segment + main_heap + numa_heaps) == 0)
|
||||||
return clib_error_return
|
return clib_error_return
|
||||||
(0, "Please supply one of api-segment, stats-segment or main-heap");
|
(0, "Need one of api-segment, stats-segment, main-heap or numa-heaps");
|
||||||
|
|
||||||
if (api_segment)
|
if (api_segment)
|
||||||
{
|
{
|
||||||
@@ -801,6 +804,7 @@ show_memory_usage (vlib_main_t * vm,
|
|||||||
vec_free (s);
|
vec_free (s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if USE_DLMALLOC == 0
|
#if USE_DLMALLOC == 0
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
foreach_vlib_main (
|
foreach_vlib_main (
|
||||||
@@ -849,6 +853,32 @@ show_memory_usage (vlib_main_t * vm,
|
|||||||
/* Restore the trace flag */
|
/* Restore the trace flag */
|
||||||
clib_mem_trace_enable_disable (was_enabled);
|
clib_mem_trace_enable_disable (was_enabled);
|
||||||
}
|
}
|
||||||
|
if (numa_heaps)
|
||||||
|
{
|
||||||
|
struct dlmallinfo mi;
|
||||||
|
void *mspace;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_LEN (clib_per_numa_mheaps); i++)
|
||||||
|
{
|
||||||
|
if (clib_per_numa_mheaps[i] == 0)
|
||||||
|
continue;
|
||||||
|
if (clib_per_numa_mheaps[i] == clib_per_cpu_mheaps[i])
|
||||||
|
{
|
||||||
|
vlib_cli_output (vm, "Numa %d uses the main heap...", i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
was_enabled = clib_mem_trace_enable_disable (0);
|
||||||
|
mspace = clib_per_numa_mheaps[i];
|
||||||
|
|
||||||
|
mi = mspace_mallinfo (mspace);
|
||||||
|
vlib_cli_output (vm, "Numa %d:", i);
|
||||||
|
vlib_cli_output (vm, " %U\n", format_page_map,
|
||||||
|
pointer_to_uword (mspace_least_addr (mspace)),
|
||||||
|
mi.arena);
|
||||||
|
vlib_cli_output (vm, " %U\n", format_mheap,
|
||||||
|
clib_per_numa_mheaps[index], verbose);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif /* USE_DLMALLOC */
|
#endif /* USE_DLMALLOC */
|
||||||
return 0;
|
return 0;
|
||||||
@@ -857,7 +887,8 @@ show_memory_usage (vlib_main_t * vm,
|
|||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
VLIB_CLI_COMMAND (show_memory_usage_command, static) = {
|
VLIB_CLI_COMMAND (show_memory_usage_command, static) = {
|
||||||
.path = "show memory",
|
.path = "show memory",
|
||||||
.short_help = "show memory [api-segment][stats-segment][verbose]",
|
.short_help = "show memory [api-segment][stats-segment][verbose]\n"
|
||||||
|
" [numa-heaps]",
|
||||||
.function = show_memory_usage,
|
.function = show_memory_usage,
|
||||||
};
|
};
|
||||||
/* *INDENT-ON* */
|
/* *INDENT-ON* */
|
||||||
@@ -905,6 +936,7 @@ enable_disable_memory_trace (vlib_main_t * vm,
|
|||||||
int api_segment = 0;
|
int api_segment = 0;
|
||||||
int stats_segment = 0;
|
int stats_segment = 0;
|
||||||
int main_heap = 0;
|
int main_heap = 0;
|
||||||
|
u32 numa_id = ~0;
|
||||||
void *oldheap;
|
void *oldheap;
|
||||||
|
|
||||||
if (!unformat_user (input, unformat_line_input, line_input))
|
if (!unformat_user (input, unformat_line_input, line_input))
|
||||||
@@ -920,6 +952,8 @@ enable_disable_memory_trace (vlib_main_t * vm,
|
|||||||
stats_segment = 1;
|
stats_segment = 1;
|
||||||
else if (unformat (line_input, "main-heap"))
|
else if (unformat (line_input, "main-heap"))
|
||||||
main_heap = 1;
|
main_heap = 1;
|
||||||
|
else if (unformat (line_input, "numa-heap %d", &numa_id))
|
||||||
|
;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
unformat_free (line_input);
|
unformat_free (line_input);
|
||||||
@@ -928,10 +962,12 @@ enable_disable_memory_trace (vlib_main_t * vm,
|
|||||||
}
|
}
|
||||||
unformat_free (line_input);
|
unformat_free (line_input);
|
||||||
|
|
||||||
if ((api_segment + stats_segment + main_heap + (enable == 0)) == 0)
|
if ((api_segment + stats_segment + main_heap + (enable == 0)
|
||||||
|
+ (numa_id != ~0)) == 0)
|
||||||
{
|
{
|
||||||
return clib_error_return
|
return clib_error_return
|
||||||
(0, "Need one of main-heap, stats-segment or api-segment");
|
(0, "Need one of main-heap, stats-segment, api-segment,\n"
|
||||||
|
"numa-heap <nn> or disable");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Turn off current trace, if any */
|
/* Turn off current trace, if any */
|
||||||
@@ -975,13 +1011,31 @@ enable_disable_memory_trace (vlib_main_t * vm,
|
|||||||
clib_mem_trace (main_heap);
|
clib_mem_trace (main_heap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (numa_id != ~0)
|
||||||
|
{
|
||||||
|
if (numa_id >= ARRAY_LEN (clib_per_numa_mheaps))
|
||||||
|
return clib_error_return (0, "Numa %d out of range", numa_id);
|
||||||
|
if (clib_per_numa_mheaps[numa_id] == 0)
|
||||||
|
return clib_error_return (0, "Numa %d heap not active", numa_id);
|
||||||
|
|
||||||
|
if (clib_per_numa_mheaps[numa_id] == clib_mem_get_heap ())
|
||||||
|
return clib_error_return (0, "Numa %d uses the main heap...",
|
||||||
|
numa_id);
|
||||||
|
current_traced_heap = clib_per_numa_mheaps[numa_id];
|
||||||
|
oldheap = clib_mem_set_heap (current_traced_heap);
|
||||||
|
clib_mem_trace (1);
|
||||||
|
clib_mem_set_heap (oldheap);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
VLIB_CLI_COMMAND (enable_disable_memory_trace_command, static) = {
|
VLIB_CLI_COMMAND (enable_disable_memory_trace_command, static) = {
|
||||||
.path = "memory-trace",
|
.path = "memory-trace",
|
||||||
.short_help = "memory-trace on|off [api-segment][stats-segment][main-heap]\n",
|
.short_help = "memory-trace on|off [api-segment][stats-segment][main-heap]\n"
|
||||||
|
" [numa-heap <numa-id>]\n",
|
||||||
.function = enable_disable_memory_trace,
|
.function = enable_disable_memory_trace,
|
||||||
};
|
};
|
||||||
/* *INDENT-ON* */
|
/* *INDENT-ON* */
|
||||||
|
@@ -577,12 +577,12 @@ vlib_worker_thread_bootstrap_fn (void *arg)
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
vlib_get_thread_core_socket (vlib_worker_thread_t * w, unsigned cpu_id)
|
vlib_get_thread_core_numa (vlib_worker_thread_t * w, unsigned cpu_id)
|
||||||
{
|
{
|
||||||
const char *sys_cpu_path = "/sys/devices/system/cpu/cpu";
|
const char *sys_cpu_path = "/sys/devices/system/cpu/cpu";
|
||||||
u8 *p = 0;
|
u8 *p = 0;
|
||||||
int core_id = -1, socket_id = -1;
|
int core_id = -1, numa_id = -1;
|
||||||
|
|
||||||
p = format (p, "%s%u/topology/core_id%c", sys_cpu_path, cpu_id, 0);
|
p = format (p, "%s%u/topology/core_id%c", sys_cpu_path, cpu_id, 0);
|
||||||
clib_sysfs_read ((char *) p, "%d", &core_id);
|
clib_sysfs_read ((char *) p, "%d", &core_id);
|
||||||
@@ -590,11 +590,11 @@ vlib_get_thread_core_socket (vlib_worker_thread_t * w, unsigned cpu_id)
|
|||||||
p =
|
p =
|
||||||
format (p, "%s%u/topology/physical_package_id%c", sys_cpu_path, cpu_id,
|
format (p, "%s%u/topology/physical_package_id%c", sys_cpu_path, cpu_id,
|
||||||
0);
|
0);
|
||||||
clib_sysfs_read ((char *) p, "%d", &socket_id);
|
clib_sysfs_read ((char *) p, "%d", &numa_id);
|
||||||
vec_free (p);
|
vec_free (p);
|
||||||
|
|
||||||
w->core_id = core_id;
|
w->core_id = core_id;
|
||||||
w->socket_id = socket_id;
|
w->numa_id = numa_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
static clib_error_t *
|
static clib_error_t *
|
||||||
@@ -602,9 +602,29 @@ vlib_launch_thread_int (void *fp, vlib_worker_thread_t * w, unsigned cpu_id)
|
|||||||
{
|
{
|
||||||
vlib_thread_main_t *tm = &vlib_thread_main;
|
vlib_thread_main_t *tm = &vlib_thread_main;
|
||||||
void *(*fp_arg) (void *) = fp;
|
void *(*fp_arg) (void *) = fp;
|
||||||
|
void *numa_heap;
|
||||||
|
|
||||||
w->cpu_id = cpu_id;
|
w->cpu_id = cpu_id;
|
||||||
vlib_get_thread_core_socket (w, cpu_id);
|
vlib_get_thread_core_numa (w, cpu_id);
|
||||||
|
os_set_numa_index (w->numa_id);
|
||||||
|
|
||||||
|
/* Set up NUMA-bound heap if indicated */
|
||||||
|
if (clib_per_numa_mheaps[w->numa_id] == 0)
|
||||||
|
{
|
||||||
|
/* If the user requested a NUMA heap, create it... */
|
||||||
|
if (tm->numa_heap_size)
|
||||||
|
{
|
||||||
|
numa_heap = clib_mem_init_thread_safe_numa
|
||||||
|
(0 /* DIY */ , tm->numa_heap_size);
|
||||||
|
clib_per_numa_mheaps[w->numa_id] = numa_heap;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Or, use the main heap */
|
||||||
|
clib_per_numa_mheaps[w->numa_id] = w->thread_mheap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (tm->cb.vlib_launch_thread_cb && !w->registration->use_pthreads)
|
if (tm->cb.vlib_launch_thread_cb && !w->registration->use_pthreads)
|
||||||
return tm->cb.vlib_launch_thread_cb (fp, (void *) w, cpu_id);
|
return tm->cb.vlib_launch_thread_cb (fp, (void *) w, cpu_id);
|
||||||
else
|
else
|
||||||
@@ -1242,6 +1262,9 @@ cpu_config (vlib_main_t * vm, unformat_input_t * input)
|
|||||||
;
|
;
|
||||||
else if (unformat (input, "skip-cores %u", &tm->skip_cores))
|
else if (unformat (input, "skip-cores %u", &tm->skip_cores))
|
||||||
;
|
;
|
||||||
|
else if (unformat (input, "numa-heap-size %U",
|
||||||
|
unformat_memory_size, &tm->numa_heap_size))
|
||||||
|
;
|
||||||
else if (unformat (input, "coremask-%s %U", &name,
|
else if (unformat (input, "coremask-%s %U", &name,
|
||||||
unformat_bitmap_mask, &bitmap) ||
|
unformat_bitmap_mask, &bitmap) ||
|
||||||
unformat (input, "corelist-%s %U", &name,
|
unformat (input, "corelist-%s %U", &name,
|
||||||
|
@@ -110,7 +110,7 @@ typedef struct
|
|||||||
long lwp;
|
long lwp;
|
||||||
int cpu_id;
|
int cpu_id;
|
||||||
int core_id;
|
int core_id;
|
||||||
int socket_id;
|
int numa_id;
|
||||||
pthread_t thread_id;
|
pthread_t thread_id;
|
||||||
} vlib_worker_thread_t;
|
} vlib_worker_thread_t;
|
||||||
|
|
||||||
@@ -338,6 +338,10 @@ typedef struct
|
|||||||
/* callbacks */
|
/* callbacks */
|
||||||
vlib_thread_callbacks_t cb;
|
vlib_thread_callbacks_t cb;
|
||||||
int extern_thread_mgmt;
|
int extern_thread_mgmt;
|
||||||
|
|
||||||
|
/* NUMA-bound heap size */
|
||||||
|
uword numa_heap_size;
|
||||||
|
|
||||||
} vlib_thread_main_t;
|
} vlib_thread_main_t;
|
||||||
|
|
||||||
extern vlib_thread_main_t vlib_thread_main;
|
extern vlib_thread_main_t vlib_thread_main;
|
||||||
@@ -613,6 +617,9 @@ void
|
|||||||
vlib_process_signal_event_mt_helper (vlib_process_signal_event_mt_args_t *
|
vlib_process_signal_event_mt_helper (vlib_process_signal_event_mt_args_t *
|
||||||
args);
|
args);
|
||||||
void vlib_rpc_call_main_thread (void *function, u8 * args, u32 size);
|
void vlib_rpc_call_main_thread (void *function, u8 * args, u32 size);
|
||||||
|
void vlib_get_thread_core_numa (vlib_worker_thread_t * w, unsigned cpu_id);
|
||||||
|
|
||||||
|
|
||||||
#endif /* included_vlib_threads_h */
|
#endif /* included_vlib_threads_h */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -67,8 +67,8 @@ show_threads_fn (vlib_main_t * vm,
|
|||||||
if (cpu_id > -1)
|
if (cpu_id > -1)
|
||||||
{
|
{
|
||||||
int core_id = w->core_id;
|
int core_id = w->core_id;
|
||||||
int socket_id = w->socket_id;
|
int numa_id = w->numa_id;
|
||||||
line = format (line, "%-7u%-7u%-7u%", cpu_id, core_id, socket_id);
|
line = format (line, "%-7u%-7u%-7u%", cpu_id, core_id, numa_id);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@@ -37,6 +37,21 @@ vl (void *p)
|
|||||||
return vec_len (p);
|
return vec_len (p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief GDB callable function: pvh - Return vector header of vector
|
||||||
|
*
|
||||||
|
* @param *p - void - address of vector
|
||||||
|
*
|
||||||
|
* @return vh - vec_header_t, the vector header
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
vec_header_t *
|
||||||
|
pvh (void *p)
|
||||||
|
{
|
||||||
|
return _vec_find (p);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief GDB callable function: pe - call pool_elts - number of elements in a pool
|
* @brief GDB callable function: pe - call pool_elts - number of elements in a pool
|
||||||
*
|
*
|
||||||
|
@@ -273,7 +273,7 @@ get_thread_data (vl_api_thread_data_t * td, int index)
|
|||||||
td->pid = htonl (w->lwp);
|
td->pid = htonl (w->lwp);
|
||||||
td->cpu_id = htonl (w->cpu_id);
|
td->cpu_id = htonl (w->cpu_id);
|
||||||
td->core = htonl (w->core_id);
|
td->core = htonl (w->core_id);
|
||||||
td->cpu_socket = htonl (w->socket_id);
|
td->cpu_socket = htonl (w->numa_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@@ -20,6 +20,7 @@
|
|||||||
#include <vppinfra/cpu.h>
|
#include <vppinfra/cpu.h>
|
||||||
#include <vlib/vlib.h>
|
#include <vlib/vlib.h>
|
||||||
#include <vlib/unix/unix.h>
|
#include <vlib/unix/unix.h>
|
||||||
|
#include <vlib/threads.h>
|
||||||
#include <vnet/plugin/plugin.h>
|
#include <vnet/plugin/plugin.h>
|
||||||
#include <vnet/ethernet/ethernet.h>
|
#include <vnet/ethernet/ethernet.h>
|
||||||
#include <vpp/app/version.h>
|
#include <vpp/app/version.h>
|
||||||
@@ -107,6 +108,7 @@ main (int argc, char *argv[])
|
|||||||
u32 size;
|
u32 size;
|
||||||
int main_core = 1;
|
int main_core = 1;
|
||||||
cpu_set_t cpuset;
|
cpu_set_t cpuset;
|
||||||
|
void *main_heap;
|
||||||
|
|
||||||
#if __x86_64__
|
#if __x86_64__
|
||||||
CLIB_UNUSED (const char *msg)
|
CLIB_UNUSED (const char *msg)
|
||||||
@@ -273,8 +275,17 @@ defaulted:
|
|||||||
vl_msg_api_set_first_available_msg_id (VL_MSG_FIRST_AVAILABLE);
|
vl_msg_api_set_first_available_msg_id (VL_MSG_FIRST_AVAILABLE);
|
||||||
|
|
||||||
/* Allocate main heap */
|
/* Allocate main heap */
|
||||||
if (clib_mem_init_thread_safe (0, main_heap_size))
|
if ((main_heap = clib_mem_init_thread_safe (0, main_heap_size)))
|
||||||
{
|
{
|
||||||
|
vlib_worker_thread_t tmp;
|
||||||
|
|
||||||
|
/* Figure out which numa runs the main thread */
|
||||||
|
vlib_get_thread_core_numa (&tmp, main_core);
|
||||||
|
__os_numa_index = tmp.numa_id;
|
||||||
|
|
||||||
|
/* and use the main heap as that numa's numa heap */
|
||||||
|
clib_mem_set_per_numa_heap (main_heap);
|
||||||
|
|
||||||
vm->init_functions_called = hash_create (0, /* value bytes */ 0);
|
vm->init_functions_called = hash_create (0, /* value bytes */ 0);
|
||||||
vpe_main_init (vm);
|
vpe_main_init (vm);
|
||||||
return vlib_unix_main (argc, argv);
|
return vlib_unix_main (argc, argv);
|
||||||
|
@@ -24,6 +24,13 @@ else(VPP_USE_DLMALLOC)
|
|||||||
set(DLMALLOC 0)
|
set(DLMALLOC 0)
|
||||||
endif(VPP_USE_DLMALLOC)
|
endif(VPP_USE_DLMALLOC)
|
||||||
|
|
||||||
|
find_library(NUMA numa)
|
||||||
|
if (NUMA)
|
||||||
|
set(NUMA_LIBRARY_FOUND 1)
|
||||||
|
else(NUMA)
|
||||||
|
set(NUMA_LIBRARY_FOUND 0)
|
||||||
|
endif()
|
||||||
|
|
||||||
configure_file(
|
configure_file(
|
||||||
${CMAKE_SOURCE_DIR}/vppinfra/config.h.in
|
${CMAKE_SOURCE_DIR}/vppinfra/config.h.in
|
||||||
${CMAKE_BINARY_DIR}/vppinfra/config.h
|
${CMAKE_BINARY_DIR}/vppinfra/config.h
|
||||||
@@ -210,7 +217,7 @@ endif(VPP_USE_DLMALLOC)
|
|||||||
|
|
||||||
add_vpp_library(vppinfra
|
add_vpp_library(vppinfra
|
||||||
SOURCES ${VPPINFRA_SRCS}
|
SOURCES ${VPPINFRA_SRCS}
|
||||||
LINK_LIBRARIES m
|
LINK_LIBRARIES m ${NUMA}
|
||||||
INSTALL_HEADERS ${VPPINFRA_HEADERS}
|
INSTALL_HEADERS ${VPPINFRA_HEADERS}
|
||||||
COMPONENT libvppinfra
|
COMPONENT libvppinfra
|
||||||
)
|
)
|
||||||
|
@@ -179,7 +179,6 @@ void BV (clib_bihash_master_init_svm)
|
|||||||
sizeof (vec_header_t) +
|
sizeof (vec_header_t) +
|
||||||
BIHASH_FREELIST_LENGTH * sizeof (u64));
|
BIHASH_FREELIST_LENGTH * sizeof (u64));
|
||||||
freelist_vh->len = BIHASH_FREELIST_LENGTH;
|
freelist_vh->len = BIHASH_FREELIST_LENGTH;
|
||||||
freelist_vh->dlmalloc_header_offset = 0xDEADBEEF;
|
|
||||||
h->sh->freelists_as_u64 =
|
h->sh->freelists_as_u64 =
|
||||||
(u64) BV (clib_bihash_get_offset) (h, freelist_vh->vector_data);
|
(u64) BV (clib_bihash_get_offset) (h, freelist_vh->vector_data);
|
||||||
h->freelists = (void *) (freelist_vh->vector_data);
|
h->freelists = (void *) (freelist_vh->vector_data);
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define USE_DLMALLOC @DLMALLOC@
|
#define USE_DLMALLOC @DLMALLOC@
|
||||||
|
#define HAVE_NUMA_LIBRARY @NUMA_LIBRARY_FOUND@
|
||||||
|
|
||||||
#define CLIB_TARGET_TRIPLET "@CMAKE_C_COMPILER_TARGET@"
|
#define CLIB_TARGET_TRIPLET "@CMAKE_C_COMPILER_TARGET@"
|
||||||
#endif
|
#endif
|
||||||
|
@@ -56,9 +56,46 @@
|
|||||||
#include <vppinfra/sanitizer.h>
|
#include <vppinfra/sanitizer.h>
|
||||||
|
|
||||||
#define CLIB_MAX_MHEAPS 256
|
#define CLIB_MAX_MHEAPS 256
|
||||||
|
#define CLIB_MAX_NUMAS 8
|
||||||
|
|
||||||
|
/* Unspecified NUMA socket */
|
||||||
|
#define VEC_NUMA_UNSPECIFIED (0xFF)
|
||||||
|
|
||||||
/* Per CPU heaps. */
|
/* Per CPU heaps. */
|
||||||
extern void *clib_per_cpu_mheaps[CLIB_MAX_MHEAPS];
|
extern void *clib_per_cpu_mheaps[CLIB_MAX_MHEAPS];
|
||||||
|
extern void *clib_per_numa_mheaps[CLIB_MAX_NUMAS];
|
||||||
|
|
||||||
|
always_inline void *
|
||||||
|
clib_mem_get_per_cpu_heap (void)
|
||||||
|
{
|
||||||
|
int cpu = os_get_thread_index ();
|
||||||
|
return clib_per_cpu_mheaps[cpu];
|
||||||
|
}
|
||||||
|
|
||||||
|
always_inline void *
|
||||||
|
clib_mem_set_per_cpu_heap (u8 * new_heap)
|
||||||
|
{
|
||||||
|
int cpu = os_get_thread_index ();
|
||||||
|
void *old = clib_per_cpu_mheaps[cpu];
|
||||||
|
clib_per_cpu_mheaps[cpu] = new_heap;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
always_inline void *
|
||||||
|
clib_mem_get_per_numa_heap (u32 numa_id)
|
||||||
|
{
|
||||||
|
ASSERT (numa_id >= 0 && numa_id < ARRAY_LEN (clib_per_numa_mheaps));
|
||||||
|
return clib_per_numa_mheaps[numa_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
always_inline void *
|
||||||
|
clib_mem_set_per_numa_heap (u8 * new_heap)
|
||||||
|
{
|
||||||
|
int numa = os_get_numa_index ();
|
||||||
|
void *old = clib_per_numa_mheaps[numa];
|
||||||
|
clib_per_numa_mheaps[numa] = new_heap;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
always_inline void
|
always_inline void
|
||||||
clib_mem_set_thread_index (void)
|
clib_mem_set_thread_index (void)
|
||||||
@@ -81,22 +118,6 @@ clib_mem_set_thread_index (void)
|
|||||||
ASSERT (__os_thread_index > 0);
|
ASSERT (__os_thread_index > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
always_inline void *
|
|
||||||
clib_mem_get_per_cpu_heap (void)
|
|
||||||
{
|
|
||||||
int cpu = os_get_thread_index ();
|
|
||||||
return clib_per_cpu_mheaps[cpu];
|
|
||||||
}
|
|
||||||
|
|
||||||
always_inline void *
|
|
||||||
clib_mem_set_per_cpu_heap (u8 * new_heap)
|
|
||||||
{
|
|
||||||
int cpu = os_get_thread_index ();
|
|
||||||
void *old = clib_per_cpu_mheaps[cpu];
|
|
||||||
clib_per_cpu_mheaps[cpu] = new_heap;
|
|
||||||
return old;
|
|
||||||
}
|
|
||||||
|
|
||||||
always_inline uword
|
always_inline uword
|
||||||
clib_mem_size_nocheck (void *p)
|
clib_mem_size_nocheck (void *p)
|
||||||
{
|
{
|
||||||
@@ -287,6 +308,7 @@ clib_mem_set_heap (void *heap)
|
|||||||
|
|
||||||
void *clib_mem_init (void *heap, uword size);
|
void *clib_mem_init (void *heap, uword size);
|
||||||
void *clib_mem_init_thread_safe (void *memory, uword memory_size);
|
void *clib_mem_init_thread_safe (void *memory, uword memory_size);
|
||||||
|
void *clib_mem_init_thread_safe_numa (void *memory, uword memory_size);
|
||||||
|
|
||||||
void clib_mem_exit (void);
|
void clib_mem_exit (void);
|
||||||
|
|
||||||
|
@@ -20,8 +20,10 @@
|
|||||||
#include <vppinfra/hash.h>
|
#include <vppinfra/hash.h>
|
||||||
#include <vppinfra/elf_clib.h>
|
#include <vppinfra/elf_clib.h>
|
||||||
#include <vppinfra/sanitizer.h>
|
#include <vppinfra/sanitizer.h>
|
||||||
|
#include <numaif.h>
|
||||||
|
|
||||||
void *clib_per_cpu_mheaps[CLIB_MAX_MHEAPS];
|
void *clib_per_cpu_mheaps[CLIB_MAX_MHEAPS];
|
||||||
|
void *clib_per_numa_mheaps[CLIB_MAX_NUMAS];
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@@ -202,8 +204,8 @@ mheap_trace_main_free (mheap_trace_main_t * tm)
|
|||||||
|
|
||||||
/* Initialize CLIB heap based on memory/size given by user.
|
/* Initialize CLIB heap based on memory/size given by user.
|
||||||
Set memory to 0 and CLIB will try to allocate its own heap. */
|
Set memory to 0 and CLIB will try to allocate its own heap. */
|
||||||
void *
|
static void *
|
||||||
clib_mem_init (void *memory, uword memory_size)
|
clib_mem_init_internal (void *memory, uword memory_size, int set_heap)
|
||||||
{
|
{
|
||||||
u8 *heap;
|
u8 *heap;
|
||||||
|
|
||||||
@@ -217,7 +219,8 @@ clib_mem_init (void *memory, uword memory_size)
|
|||||||
|
|
||||||
CLIB_MEM_POISON (mspace_least_addr (heap), mspace_footprint (heap));
|
CLIB_MEM_POISON (mspace_least_addr (heap), mspace_footprint (heap));
|
||||||
|
|
||||||
clib_mem_set_heap (heap);
|
if (set_heap)
|
||||||
|
clib_mem_set_heap (heap);
|
||||||
|
|
||||||
if (mheap_trace_main.lock == 0)
|
if (mheap_trace_main.lock == 0)
|
||||||
clib_spinlock_init (&mheap_trace_main.lock);
|
clib_spinlock_init (&mheap_trace_main.lock);
|
||||||
@@ -225,10 +228,63 @@ clib_mem_init (void *memory, uword memory_size)
|
|||||||
return heap;
|
return heap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
clib_mem_init (void *memory, uword memory_size)
|
||||||
|
{
|
||||||
|
return clib_mem_init_internal (memory, memory_size,
|
||||||
|
1 /* do clib_mem_set_heap */ );
|
||||||
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
clib_mem_init_thread_safe (void *memory, uword memory_size)
|
clib_mem_init_thread_safe (void *memory, uword memory_size)
|
||||||
{
|
{
|
||||||
return clib_mem_init (memory, memory_size);
|
return clib_mem_init_internal (memory, memory_size,
|
||||||
|
1 /* do clib_mem_set_heap */ );
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
clib_mem_init_thread_safe_numa (void *memory, uword memory_size)
|
||||||
|
{
|
||||||
|
void *heap;
|
||||||
|
unsigned long this_numa;
|
||||||
|
|
||||||
|
heap =
|
||||||
|
clib_mem_init_internal (memory, memory_size,
|
||||||
|
0 /* do NOT clib_mem_set_heap */ );
|
||||||
|
|
||||||
|
ASSERT (heap);
|
||||||
|
|
||||||
|
this_numa = os_get_numa_index ();
|
||||||
|
|
||||||
|
#if HAVE_NUMA_LIBRARY > 0
|
||||||
|
unsigned long nodemask = 1 << this_numa;
|
||||||
|
void *page_base;
|
||||||
|
unsigned long page_mask;
|
||||||
|
long rv;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bind the heap to the current thread's NUMA node.
|
||||||
|
* heap is not naturally page-aligned, so fix it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
page_mask = ~(clib_mem_get_page_size () - 1);
|
||||||
|
page_base = (void *) (((unsigned long) heap) & page_mask);
|
||||||
|
|
||||||
|
clib_warning ("Bind heap at %llx size %llx to NUMA numa %d",
|
||||||
|
page_base, memory_size, this_numa);
|
||||||
|
|
||||||
|
rv = mbind (page_base, memory_size, MPOL_BIND /* mode */ ,
|
||||||
|
&nodemask /* nodemask */ ,
|
||||||
|
BITS (nodemask) /* max node number */ ,
|
||||||
|
MPOL_MF_MOVE /* flags */ );
|
||||||
|
|
||||||
|
if (rv < 0)
|
||||||
|
clib_unix_warning ("mbind");
|
||||||
|
#else
|
||||||
|
clib_warning ("mbind unavailable, can't bind to numa %d", this_numa);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return heap;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 *
|
u8 *
|
||||||
|
@@ -57,6 +57,7 @@ void os_out_of_memory (void);
|
|||||||
f64 os_cpu_clock_frequency (void);
|
f64 os_cpu_clock_frequency (void);
|
||||||
|
|
||||||
extern __thread uword __os_thread_index;
|
extern __thread uword __os_thread_index;
|
||||||
|
extern __thread uword __os_numa_index;
|
||||||
|
|
||||||
static_always_inline uword
|
static_always_inline uword
|
||||||
os_get_thread_index (void)
|
os_get_thread_index (void)
|
||||||
@@ -70,6 +71,18 @@ os_set_thread_index (uword thread_index)
|
|||||||
__os_thread_index = thread_index;
|
__os_thread_index = thread_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static_always_inline uword
|
||||||
|
os_get_numa_index (void)
|
||||||
|
{
|
||||||
|
return __os_numa_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
static_always_inline void
|
||||||
|
os_set_numa_index (uword numa_index)
|
||||||
|
{
|
||||||
|
__os_numa_index = numa_index;
|
||||||
|
}
|
||||||
|
|
||||||
static_always_inline uword
|
static_always_inline uword
|
||||||
os_get_cpu_number (void) __attribute__ ((deprecated));
|
os_get_cpu_number (void) __attribute__ ((deprecated));
|
||||||
|
|
||||||
|
@@ -185,12 +185,13 @@ pool_free_elts (void *v)
|
|||||||
|
|
||||||
First search free list. If nothing is free extend vector of objects.
|
First search free list. If nothing is free extend vector of objects.
|
||||||
*/
|
*/
|
||||||
#define _pool_get_aligned_internal(P,E,A,Z) \
|
#define _pool_get_aligned_internal_numa(P,E,A,Z,N) \
|
||||||
do { \
|
do { \
|
||||||
pool_header_t * _pool_var (p) = pool_header (P); \
|
pool_header_t * _pool_var (p) = pool_header (P); \
|
||||||
uword _pool_var (l); \
|
uword _pool_var (l); \
|
||||||
\
|
\
|
||||||
STATIC_ASSERT(A==0 || ((A % sizeof(P[0]))==0) || ((sizeof(P[0]) % A) == 0), \
|
STATIC_ASSERT(A==0 || ((A % sizeof(P[0]))==0) \
|
||||||
|
|| ((sizeof(P[0]) % A) == 0), \
|
||||||
"Pool aligned alloc of incorrectly sized object"); \
|
"Pool aligned alloc of incorrectly sized object"); \
|
||||||
_pool_var (l) = 0; \
|
_pool_var (l) = 0; \
|
||||||
if (P) \
|
if (P) \
|
||||||
@@ -199,11 +200,12 @@ do { \
|
|||||||
if (_pool_var (l) > 0) \
|
if (_pool_var (l) > 0) \
|
||||||
{ \
|
{ \
|
||||||
/* Return free element from free list. */ \
|
/* Return free element from free list. */ \
|
||||||
uword _pool_var (i) = _pool_var (p)->free_indices[_pool_var (l) - 1]; \
|
uword _pool_var (i) = \
|
||||||
|
_pool_var (p)->free_indices[_pool_var (l) - 1]; \
|
||||||
(E) = (P) + _pool_var (i); \
|
(E) = (P) + _pool_var (i); \
|
||||||
_pool_var (p)->free_bitmap = \
|
_pool_var (p)->free_bitmap = \
|
||||||
clib_bitmap_andnoti_notrim (_pool_var (p)->free_bitmap, \
|
clib_bitmap_andnoti_notrim (_pool_var (p)->free_bitmap, \
|
||||||
_pool_var (i)); \
|
_pool_var (i)); \
|
||||||
_vec_len (_pool_var (p)->free_indices) = _pool_var (l) - 1; \
|
_vec_len (_pool_var (p)->free_indices) = _pool_var (l) - 1; \
|
||||||
CLIB_MEM_UNPOISON((E), sizeof((E)[0])); \
|
CLIB_MEM_UNPOISON((E), sizeof((E)[0])); \
|
||||||
} \
|
} \
|
||||||
@@ -216,17 +218,30 @@ do { \
|
|||||||
os_out_of_memory(); \
|
os_out_of_memory(); \
|
||||||
} \
|
} \
|
||||||
/* Nothing on free list, make a new element and return it. */ \
|
/* Nothing on free list, make a new element and return it. */ \
|
||||||
P = _vec_resize (P, \
|
P = _vec_resize_numa (P, \
|
||||||
/* length_increment */ 1, \
|
/* length_increment */ 1, \
|
||||||
/* new size */ (vec_len (P) + 1) * sizeof (P[0]), \
|
/* new size */ (vec_len (P) + 1) * sizeof (P[0]), \
|
||||||
pool_aligned_header_bytes, \
|
pool_aligned_header_bytes, \
|
||||||
/* align */ (A)); \
|
/* align */ (A), \
|
||||||
|
/* numa */ (N)); \
|
||||||
E = vec_end (P) - 1; \
|
E = vec_end (P) - 1; \
|
||||||
} \
|
} \
|
||||||
if (Z) \
|
if (Z) \
|
||||||
memset(E, 0, sizeof(*E)); \
|
memset(E, 0, sizeof(*E)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#define pool_get_aligned_zero_numa(P,E,A,Z,S) \
|
||||||
|
_pool_get_aligned_internal_numa(P,E,A,Z,S)
|
||||||
|
|
||||||
|
#define pool_get_aligned_numa(P,E,A,S) \
|
||||||
|
_pool_get_aligned_internal_numa(P,E,A,0/*zero*/,S)
|
||||||
|
|
||||||
|
#define pool_get_numa(P,E,S) \
|
||||||
|
_pool_get_aligned_internal_numa(P,E,0/*align*/,0/*zero*/,S)
|
||||||
|
|
||||||
|
#define _pool_get_aligned_internal(P,E,A,Z) \
|
||||||
|
_pool_get_aligned_internal_numa(P,E,A,Z,VEC_NUMA_UNSPECIFIED)
|
||||||
|
|
||||||
/** Allocate an object E from a pool P with alignment A */
|
/** Allocate an object E from a pool P with alignment A */
|
||||||
#define pool_get_aligned(P,E,A) _pool_get_aligned_internal(P,E,A,0)
|
#define pool_get_aligned(P,E,A) _pool_get_aligned_internal(P,E,A,0)
|
||||||
|
|
||||||
|
@@ -46,6 +46,7 @@
|
|||||||
#include <stdio.h> /* for sprintf */
|
#include <stdio.h> /* for sprintf */
|
||||||
|
|
||||||
__thread uword __os_thread_index = 0;
|
__thread uword __os_thread_index = 0;
|
||||||
|
__thread uword __os_numa_index = 0;
|
||||||
|
|
||||||
clib_error_t *
|
clib_error_t *
|
||||||
clib_file_n_bytes (char *file, uword * result)
|
clib_file_n_bytes (char *file, uword * result)
|
||||||
|
@@ -44,16 +44,24 @@ void *
|
|||||||
vec_resize_allocate_memory (void *v,
|
vec_resize_allocate_memory (void *v,
|
||||||
word length_increment,
|
word length_increment,
|
||||||
uword data_bytes,
|
uword data_bytes,
|
||||||
uword header_bytes, uword data_align)
|
uword header_bytes, uword data_align,
|
||||||
|
uword numa_id)
|
||||||
{
|
{
|
||||||
vec_header_t *vh = _vec_find (v);
|
vec_header_t *vh = _vec_find (v);
|
||||||
uword old_alloc_bytes, new_alloc_bytes;
|
uword old_alloc_bytes, new_alloc_bytes;
|
||||||
void *old, *new;
|
void *old, *new;
|
||||||
|
void *oldheap;
|
||||||
|
|
||||||
header_bytes = vec_header_bytes (header_bytes);
|
header_bytes = vec_header_bytes (header_bytes);
|
||||||
|
|
||||||
data_bytes += header_bytes;
|
data_bytes += header_bytes;
|
||||||
|
|
||||||
|
if (PREDICT_FALSE (numa_id != VEC_NUMA_UNSPECIFIED))
|
||||||
|
{
|
||||||
|
oldheap = clib_mem_get_per_cpu_heap ();
|
||||||
|
clib_mem_set_per_cpu_heap (clib_mem_get_per_numa_heap (numa_id));
|
||||||
|
}
|
||||||
|
|
||||||
if (!v)
|
if (!v)
|
||||||
{
|
{
|
||||||
new = clib_mem_alloc_aligned_at_offset (data_bytes, data_align, header_bytes, 1 /* yes, call os_out_of_memory */
|
new = clib_mem_alloc_aligned_at_offset (data_bytes, data_align, header_bytes, 1 /* yes, call os_out_of_memory */
|
||||||
@@ -64,6 +72,9 @@ vec_resize_allocate_memory (void *v,
|
|||||||
CLIB_MEM_POISON (new + data_bytes, new_alloc_bytes - data_bytes);
|
CLIB_MEM_POISON (new + data_bytes, new_alloc_bytes - data_bytes);
|
||||||
v = new + header_bytes;
|
v = new + header_bytes;
|
||||||
_vec_len (v) = length_increment;
|
_vec_len (v) = length_increment;
|
||||||
|
_vec_numa (v) = numa_id;
|
||||||
|
if (PREDICT_FALSE (numa_id != VEC_NUMA_UNSPECIFIED))
|
||||||
|
clib_mem_set_per_cpu_heap (oldheap);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,6 +90,8 @@ vec_resize_allocate_memory (void *v,
|
|||||||
if (data_bytes <= old_alloc_bytes)
|
if (data_bytes <= old_alloc_bytes)
|
||||||
{
|
{
|
||||||
CLIB_MEM_UNPOISON (v, data_bytes);
|
CLIB_MEM_UNPOISON (v, data_bytes);
|
||||||
|
if (PREDICT_FALSE (numa_id != VEC_NUMA_UNSPECIFIED))
|
||||||
|
clib_mem_set_per_cpu_heap (oldheap);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,6 +123,10 @@ vec_resize_allocate_memory (void *v,
|
|||||||
memset (v + old_alloc_bytes, 0, new_alloc_bytes - old_alloc_bytes);
|
memset (v + old_alloc_bytes, 0, new_alloc_bytes - old_alloc_bytes);
|
||||||
CLIB_MEM_POISON (new + data_bytes, new_alloc_bytes - data_bytes);
|
CLIB_MEM_POISON (new + data_bytes, new_alloc_bytes - data_bytes);
|
||||||
|
|
||||||
|
_vec_numa ((v + header_bytes)) = numa_id;
|
||||||
|
if (PREDICT_FALSE (numa_id != VEC_NUMA_UNSPECIFIED))
|
||||||
|
clib_mem_set_per_cpu_heap (oldheap);
|
||||||
|
|
||||||
return v + header_bytes;
|
return v + header_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -96,12 +96,14 @@
|
|||||||
@param data_bytes requested size in bytes
|
@param data_bytes requested size in bytes
|
||||||
@param header_bytes header size in bytes (may be zero)
|
@param header_bytes header size in bytes (may be zero)
|
||||||
@param data_align alignment (may be zero)
|
@param data_align alignment (may be zero)
|
||||||
|
@param numa_id numa id (may be zero)
|
||||||
@return v_prime pointer to resized vector, may or may not equal v
|
@return v_prime pointer to resized vector, may or may not equal v
|
||||||
*/
|
*/
|
||||||
void *vec_resize_allocate_memory (void *v,
|
void *vec_resize_allocate_memory (void *v,
|
||||||
word length_increment,
|
word length_increment,
|
||||||
uword data_bytes,
|
uword data_bytes,
|
||||||
uword header_bytes, uword data_align);
|
uword header_bytes, uword data_align,
|
||||||
|
uword numa_id);
|
||||||
|
|
||||||
/** \brief Low-level vector resize function, usually not called directly
|
/** \brief Low-level vector resize function, usually not called directly
|
||||||
|
|
||||||
@@ -110,19 +112,25 @@ void *vec_resize_allocate_memory (void *v,
|
|||||||
@param data_bytes requested size in bytes
|
@param data_bytes requested size in bytes
|
||||||
@param header_bytes header size in bytes (may be zero)
|
@param header_bytes header size in bytes (may be zero)
|
||||||
@param data_align alignment (may be zero)
|
@param data_align alignment (may be zero)
|
||||||
|
@param numa_id (may be ~0)
|
||||||
@return v_prime pointer to resized vector, may or may not equal v
|
@return v_prime pointer to resized vector, may or may not equal v
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define _vec_resize(V,L,DB,HB,A) \
|
#define _vec_resize_numa(V,L,DB,HB,A,S) \
|
||||||
_vec_resize_inline(V,L,DB,HB,clib_max((__alignof__((V)[0])),(A)))
|
_vec_resize_inline(V,L,DB,HB,clib_max((__alignof__((V)[0])),(A)),(S))
|
||||||
|
|
||||||
|
#define _vec_resize(V,L,DB,HB,A) \
|
||||||
|
_vec_resize_numa(V,L,DB,HB,A,VEC_NUMA_UNSPECIFIED)
|
||||||
|
|
||||||
always_inline void *
|
always_inline void *
|
||||||
_vec_resize_inline (void *v,
|
_vec_resize_inline (void *v,
|
||||||
word length_increment,
|
word length_increment,
|
||||||
uword data_bytes, uword header_bytes, uword data_align)
|
uword data_bytes, uword header_bytes, uword data_align,
|
||||||
|
uword numa_id)
|
||||||
{
|
{
|
||||||
vec_header_t *vh = _vec_find (v);
|
vec_header_t *vh = _vec_find (v);
|
||||||
uword new_data_bytes, aligned_header_bytes;
|
uword new_data_bytes, aligned_header_bytes;
|
||||||
|
void *oldheap;
|
||||||
|
|
||||||
aligned_header_bytes = vec_header_bytes (header_bytes);
|
aligned_header_bytes = vec_header_bytes (header_bytes);
|
||||||
|
|
||||||
@@ -132,6 +140,12 @@ _vec_resize_inline (void *v,
|
|||||||
{
|
{
|
||||||
void *p = v - aligned_header_bytes;
|
void *p = v - aligned_header_bytes;
|
||||||
|
|
||||||
|
if (PREDICT_FALSE (numa_id != VEC_NUMA_UNSPECIFIED))
|
||||||
|
{
|
||||||
|
oldheap = clib_mem_get_per_cpu_heap ();
|
||||||
|
clib_mem_set_per_cpu_heap (clib_mem_get_per_numa_heap (numa_id));
|
||||||
|
}
|
||||||
|
|
||||||
/* Vector header must start heap object. */
|
/* Vector header must start heap object. */
|
||||||
ASSERT (clib_mem_is_heap_object (p));
|
ASSERT (clib_mem_is_heap_object (p));
|
||||||
|
|
||||||
@@ -140,15 +154,19 @@ _vec_resize_inline (void *v,
|
|||||||
{
|
{
|
||||||
CLIB_MEM_UNPOISON (v, data_bytes);
|
CLIB_MEM_UNPOISON (v, data_bytes);
|
||||||
vh->len += length_increment;
|
vh->len += length_increment;
|
||||||
|
if (PREDICT_FALSE (numa_id != VEC_NUMA_UNSPECIFIED))
|
||||||
|
clib_mem_set_per_cpu_heap (oldheap);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
if (PREDICT_FALSE (numa_id != VEC_NUMA_UNSPECIFIED))
|
||||||
|
clib_mem_set_per_cpu_heap (oldheap);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Slow path: call helper function. */
|
/* Slow path: call helper function. */
|
||||||
return vec_resize_allocate_memory (v, length_increment, data_bytes,
|
return vec_resize_allocate_memory (v, length_increment, data_bytes,
|
||||||
header_bytes,
|
header_bytes,
|
||||||
clib_max (sizeof (vec_header_t),
|
clib_max (sizeof (vec_header_t),
|
||||||
data_align));
|
data_align), numa_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \brief Determine if vector will resize with next allocation
|
/** \brief Determine if vector will resize with next allocation
|
||||||
@@ -221,16 +239,32 @@ clib_mem_is_vec (void *v)
|
|||||||
@param N number of elements to add
|
@param N number of elements to add
|
||||||
@param H header size in bytes (may be zero)
|
@param H header size in bytes (may be zero)
|
||||||
@param A alignment (may be zero)
|
@param A alignment (may be zero)
|
||||||
|
@param S numa_id (may be zero)
|
||||||
@return V (value-result macro parameter)
|
@return V (value-result macro parameter)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define vec_resize_ha(V,N,H,A) \
|
#define vec_resize_has(V,N,H,A,S) \
|
||||||
do { \
|
do { \
|
||||||
word _v(n) = (N); \
|
word _v(n) = (N); \
|
||||||
word _v(l) = vec_len (V); \
|
word _v(l) = vec_len (V); \
|
||||||
V = _vec_resize ((V), _v(n), (_v(l) + _v(n)) * sizeof ((V)[0]), (H), (A)); \
|
V = _vec_resize_numa ((V), _v(n), \
|
||||||
|
(_v(l) + _v(n)) * sizeof ((V)[0]), \
|
||||||
|
(H), (A),(S)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
/** \brief Resize a vector (less general version).
|
||||||
|
Add N elements to end of given vector V, return pointer to start of vector.
|
||||||
|
Vector will have room for H header bytes and will have user's data aligned
|
||||||
|
at alignment A (rounded to next power of 2).
|
||||||
|
|
||||||
|
@param V pointer to a vector
|
||||||
|
@param N number of elements to add
|
||||||
|
@param H header size in bytes (may be zero)
|
||||||
|
@param A alignment (may be zero)
|
||||||
|
@return V (value-result macro parameter)
|
||||||
|
*/
|
||||||
|
#define vec_resize_ha(V,N,H,A) vec_resize_has(V,N,H,A,VEC_NUMA_UNSPECIFIED)
|
||||||
|
|
||||||
/** \brief Resize a vector (no header, unspecified alignment)
|
/** \brief Resize a vector (no header, unspecified alignment)
|
||||||
Add N elements to end of given vector V, return pointer to start of vector.
|
Add N elements to end of given vector V, return pointer to start of vector.
|
||||||
Vector will have room for H header bytes and will have user's data aligned
|
Vector will have room for H header bytes and will have user's data aligned
|
||||||
@@ -352,22 +386,35 @@ do { \
|
|||||||
@param V pointer to a vector
|
@param V pointer to a vector
|
||||||
@param H size of header in bytes
|
@param H size of header in bytes
|
||||||
@param A alignment (may be zero)
|
@param A alignment (may be zero)
|
||||||
|
@param S numa (may be VEC_NUMA_UNSPECIFIED)
|
||||||
|
|
||||||
@return Vdup copy of vector
|
@return Vdup copy of vector
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define vec_dup_ha(V,H,A) \
|
#define vec_dup_ha_numa(V,H,A,S) \
|
||||||
({ \
|
({ \
|
||||||
__typeof__ ((V)[0]) * _v(v) = 0; \
|
__typeof__ ((V)[0]) * _v(v) = 0; \
|
||||||
uword _v(l) = vec_len (V); \
|
uword _v(l) = vec_len (V); \
|
||||||
if (_v(l) > 0) \
|
if (_v(l) > 0) \
|
||||||
{ \
|
{ \
|
||||||
vec_resize_ha (_v(v), _v(l), (H), (A)); \
|
vec_resize_has (_v(v), _v(l), (H), (A), (S)); \
|
||||||
clib_memcpy_fast (_v(v), (V), _v(l) * sizeof ((V)[0]));\
|
clib_memcpy_fast (_v(v), (V), _v(l) * sizeof ((V)[0]));\
|
||||||
} \
|
} \
|
||||||
_v(v); \
|
_v(v); \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/** \brief Return copy of vector (VEC_NUMA_UNSPECIFIED).
|
||||||
|
|
||||||
|
@param V pointer to a vector
|
||||||
|
@param H size of header in bytes
|
||||||
|
@param A alignment (may be zero)
|
||||||
|
|
||||||
|
@return Vdup copy of vector
|
||||||
|
*/
|
||||||
|
#define vec_dup_ha(V,H,A) \
|
||||||
|
vec_dup_ha_numa(V,H,A,VEC_NUMA_UNSPECIFIED)
|
||||||
|
|
||||||
|
|
||||||
/** \brief Return copy of vector (no header, no alignment)
|
/** \brief Return copy of vector (no header, no alignment)
|
||||||
|
|
||||||
@param V pointer to a vector
|
@param V pointer to a vector
|
||||||
@@ -412,24 +459,40 @@ do { \
|
|||||||
@param I vector index which will be valid upon return
|
@param I vector index which will be valid upon return
|
||||||
@param H header size in bytes (may be zero)
|
@param H header size in bytes (may be zero)
|
||||||
@param A alignment (may be zero)
|
@param A alignment (may be zero)
|
||||||
|
@param N numa_id (may be zero)
|
||||||
@return V (value-result macro parameter)
|
@return V (value-result macro parameter)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define vec_validate_ha(V,I,H,A) \
|
#define vec_validate_han(V,I,H,A,N) \
|
||||||
do { \
|
do { \
|
||||||
STATIC_ASSERT(A==0 || ((A % sizeof(V[0]))==0) || ((sizeof(V[0]) % A) == 0),\
|
void *oldheap; \
|
||||||
"vector validate aligned on incorrectly sized object"); \
|
STATIC_ASSERT(A==0 || ((A % sizeof(V[0]))==0) \
|
||||||
word _v(i) = (I); \
|
|| ((sizeof(V[0]) % A) == 0), \
|
||||||
word _v(l) = vec_len (V); \
|
"vector validate aligned on incorrectly sized object"); \
|
||||||
if (_v(i) >= _v(l)) \
|
word _v(i) = (I); \
|
||||||
{ \
|
word _v(l) = vec_len (V); \
|
||||||
vec_resize_ha ((V), 1 + (_v(i) - _v(l)), (H), (A)); \
|
if (_v(i) >= _v(l)) \
|
||||||
/* Must zero new space since user may have previously \
|
{ \
|
||||||
used e.g. _vec_len (v) -= 10 */ \
|
/* switch to the per-numa heap if directed */ \
|
||||||
clib_memset ((V) + _v(l), 0, (1 + (_v(i) - _v(l))) * sizeof ((V)[0])); \
|
if (PREDICT_FALSE(N != VEC_NUMA_UNSPECIFIED)) \
|
||||||
} \
|
{ \
|
||||||
|
oldheap = clib_mem_get_per_cpu_heap(); \
|
||||||
|
clib_mem_set_per_cpu_heap (clib_mem_get_per_numa_heap(N)); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
vec_resize_ha ((V), 1 + (_v(i) - _v(l)), (H), (A)); \
|
||||||
|
/* Must zero new space since user may have previously \
|
||||||
|
used e.g. _vec_len (v) -= 10 */ \
|
||||||
|
clib_memset ((V) + _v(l), 0, \
|
||||||
|
(1 + (_v(i) - _v(l))) * sizeof ((V)[0])); \
|
||||||
|
/* Switch back to the global heap */ \
|
||||||
|
if (PREDICT_FALSE (N != VEC_NUMA_UNSPECIFIED)) \
|
||||||
|
clib_mem_set_per_cpu_heap (oldheap); \
|
||||||
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#define vec_validate_ha(V,I,H,A) vec_validate_han(V,I,H,A,VEC_NUMA_UNSPECIFIED)
|
||||||
|
|
||||||
/** \brief Make sure vector is long enough for given index
|
/** \brief Make sure vector is long enough for given index
|
||||||
(no header, unspecified alignment)
|
(no header, unspecified alignment)
|
||||||
|
|
||||||
|
@@ -58,11 +58,14 @@ typedef struct
|
|||||||
u64 len;
|
u64 len;
|
||||||
#else
|
#else
|
||||||
u32 len; /**< Number of elements in vector (NOT its allocated length). */
|
u32 len; /**< Number of elements in vector (NOT its allocated length). */
|
||||||
u32 dlmalloc_header_offset; /**< offset to memory allocator offset */
|
u8 numa_id; /**< NUMA id */
|
||||||
|
u8 vpad[3]; /**< pad to 8 bytes */
|
||||||
#endif
|
#endif
|
||||||
u8 vector_data[0]; /**< Vector data . */
|
u8 vector_data[0]; /**< Vector data . */
|
||||||
} vec_header_t;
|
} vec_header_t;
|
||||||
|
|
||||||
|
#define VEC_NUMA_UNSPECIFIED (0xFF)
|
||||||
|
|
||||||
/** \brief Find the vector header
|
/** \brief Find the vector header
|
||||||
|
|
||||||
Given the user's pointer to a vector, find the corresponding
|
Given the user's pointer to a vector, find the corresponding
|
||||||
@@ -128,7 +131,7 @@ vec_aligned_header_end (void *v, uword header_bytes, uword align)
|
|||||||
|
|
||||||
/** \brief Number of elements in vector (lvalue-capable)
|
/** \brief Number of elements in vector (lvalue-capable)
|
||||||
|
|
||||||
_vec_len (v) does not check for null, but can be used as a lvalue
|
_vec_len (v) does not check for null, but can be used as an lvalue
|
||||||
(e.g. _vec_len (v) = 99).
|
(e.g. _vec_len (v) = 99).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -142,6 +145,20 @@ vec_aligned_header_end (void *v, uword header_bytes, uword align)
|
|||||||
|
|
||||||
#define vec_len(v) ((v) ? _vec_len(v) : 0)
|
#define vec_len(v) ((v) ? _vec_len(v) : 0)
|
||||||
|
|
||||||
|
/** \brief Vector's NUMA id (lvalue-capable)
|
||||||
|
|
||||||
|
_vec_numa(v) does not check for null, but can be used as an lvalue
|
||||||
|
(e.g. _vec_numa(v) = 1).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _vec_numa(v) (_vec_find(v)->numa_id)
|
||||||
|
|
||||||
|
/** \brief Return vector's NUMA ID (rvalue-only, NULL tolerant)
|
||||||
|
vec_numa(v) checks for NULL, but cannot be used as an lvalue.
|
||||||
|
*/
|
||||||
|
#define vec_numa(v) ((v) ? _vec_numa(v) : 0)
|
||||||
|
|
||||||
|
|
||||||
/** \brief Number of data bytes in vector. */
|
/** \brief Number of data bytes in vector. */
|
||||||
|
|
||||||
#define vec_bytes(v) (vec_len (v) * sizeof (v[0]))
|
#define vec_bytes(v) (vec_len (v) * sizeof (v[0]))
|
||||||
@@ -208,6 +225,17 @@ for (var = vec_end (vec) - 1; var >= (vec); var--)
|
|||||||
#define vec_foreach_index_backwards(var,v) \
|
#define vec_foreach_index_backwards(var,v) \
|
||||||
for ((var) = vec_len((v)) - 1; (var) >= 0; (var)--)
|
for ((var) = vec_len((v)) - 1; (var) >= 0; (var)--)
|
||||||
|
|
||||||
|
/** \brief return the NUMA index for a vector */
|
||||||
|
always_inline uword
|
||||||
|
vec_get_numa (void *v)
|
||||||
|
{
|
||||||
|
vec_header_t *vh;
|
||||||
|
if (v == 0)
|
||||||
|
return 0;
|
||||||
|
vh = _vec_find (v);
|
||||||
|
return vh->numa_id;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* included_clib_vec_bootstrap_h */
|
#endif /* included_clib_vec_bootstrap_h */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Reference in New Issue
Block a user