Multi-Architecture Arbitrary Function Cookbook

Optimizing arbitrary functions for multiple architectures is simple enough, and very similar to process used to produce multi-architecture graph node dispatch functions.

As with multi-architecture graph nodes, we compile source files multiple times, generating multiple implementations of the original function, and a public selector function.

Details

Decorate function definitions with CLIB_MARCH_FN macros. For example:

Change the original function prototype…

u32 vlib_frame_alloc_to_node (vlib_main_t * vm, u32 to_node_index,
                              u32 frame_flags)

…by recasting the function name and return type as the first two arguments to the CLIB_MARCH_FN macro:

CLIB_MARCH_FN (vlib_frame_alloc_to_node, u32, vlib_main_t * vm,
               u32 to_node_index, u32 frame_flags)

In the actual vpp image, several versions of vlib_frame_alloc_to_node will appear: vlib_frame_alloc_to_node_avx2, vlib_frame_alloc_to_node_avx512, and so forth.

For each multi-architecture function, use the CLIB_MARCH_FN_SELECT macro to help generate the one-and-only multi-architecture selector function:

#ifndef CLIB_MARCH_VARIANT
u32
vlib_frame_alloc_to_node (vlib_main_t * vm, u32 to_node_index,
                      u32 frame_flags)
{
  return CLIB_MARCH_FN_SELECT (vlib_frame_alloc_to_node)
    (vm, to_node_index, frame_flags);
}
#endif /* CLIB_MARCH_VARIANT */

Once bound, the multi-architecture selector function is about as expensive as an indirect function call; which is to say: not very expensive.

Modify CMakeLists.txt

If the component in question already lists “MULTIARCH_SOURCES”, simply add the indicated .c file to the list. Otherwise, add as shown below. Note that the added file “new_multiarch_node.c” should appear in both SOURCES and MULTIARCH_SOURCES:

add_vpp_plugin(myplugin
  SOURCES
  multiarch_code.c
  ...

  MULTIARCH_SOURCES
  multiarch_code.c
  ...
 )

A Word to the Wise

A file which liberally mixes functions worth compiling for multiple architectures and functions which are not will end up full of #ifndef CLIB_MARCH_VARIANT conditionals. This won’t do a thing to make the code look any better.

Depending on requirements, it may make sense to move functions to (new) files to reduce complexity and/or improve legibility of the resulting code.