aboutsummaryrefslogtreecommitdiffstats
path: root/docs/developer/corearchitecture/multiarch/arbfns.rst
blob: d469bd8a1401eb58f6d8e54cfb494afde7ae64e8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
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.