aboutsummaryrefslogtreecommitdiffstats
path: root/docs/perf-triggers-design.rst
blob: 4a0232cde0fb9983a5f1a42bf07578b7cd7d8bc9 (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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
Introduction
------------

Previous gerrit triggers for performance tests (
*vpp-csit-verify-hw-perf-{branch}* and *csit-vpp-verify-hw-perf-{branch}*) are
listed in [1]_ with jjb definition in [2]_. Mapping of triggers to CSIT test RF
tags [4]_ driving the selection of test cases for execution is listed in [3]_.

Previous mappings of trigger to RF tags
---------------------------------------

(vpp-csit job) vpp-verify-perf-{**keyword**} OR (csit-vpp job) verify-perf-{**keyword**}
  - **acl**:
     - 'mrrANDnic_intel-x520-da2AND1t1cANDacl'
     - 'mrrANDnic_intel-x520-da2AND2t2cANDacl'
  - **ip4**:
     - 'mrrANDnic_intel-x520-da2AND1t1cANDip4base'
     - 'mrrANDnic_intel-x520-da2AND1t1cANDip4fwdANDfib_2m'
  - **ip6**
     - 'mrrANDnic_intel-x520-da2AND1t1cANDip6base'
     - 'mrrANDnic_intel-x520-da2AND1t1cANDip6fwdANDfib_2m'
  - **ipsechw**
     - 'pdrdiscANDnic_intel-xl710AND1t1cANDipsechw'
     - 'pdrdiscANDnic_intel-xl710AND2t2cANDipsechw'
     - 'mrrANDnic_intel-xl710AND1t1cANDipsechw'
     - 'mrrANDnic_intel-xl710AND2t2cANDipsechw'
  - **l2**
     - 'mrrANDnic_intel-x520-da2AND1t1cANDl2xcbase'
     - 'mrrANDnic_intel-x520-da2AND1t1cANDl2bdbase'
     - 'mrrANDnic_intel-x520-da2AND1t1cANDdot1q'
     - '!lbond_dpdk'
  - **lisp**
     - 'mrrANDnic_intel-x520-da2AND1t1cANDlisp'
  - **memif**
     - 'pdrdiscANDnic_intel-x520-da2AND1t1cANDmemif'
     - 'pdrdiscANDnic_intel-x520-da2AND2t2cANDmemif'
     - 'mrrANDnic_intel-x520-da2AND1t1cANDmemif'
     - 'mrrANDnic_intel-x520-da2AND2t2cANDmemif'
  - **vhost**
     - 'mrrANDnic_intel-x520-da2AND1t1cANDvhost'
     - '!lbond_dpdk'
  - **vxlan**
     - 'mrrANDnic_intel-x520-da2AND1t1cANDvxlan'
  - **srv6**
     - 'mrrANDsrv6AND1t1c'
     - 'mrrANDsrv6AND2t2c'

Proposal for mapping triggers to RF tags
----------------------------------------

*Goal*
  make it simpler to use, scalable, parametrize and prepare for full CI/CD
  automation.

*Syntax*
  trigger_keyword [{tag1} {tag2}AND{tag3} !{tag4} !{tag5}]

*Inputs*
  - trigger_keyword for vpp-* jobs: 'perftest'
  - trigger_keyword for csit-* jobs: 'csit-perftest'
  - tags: existing CSIT tags [4]_ i.e. ip4base, ip6base, iacldst, memif

Set of default tags appended to user input, under control by CSIT
  - always-on for vpp-csit*.job: 'mrr' 'nic_intel_x710-da2' '1t1c'
  - if input with no tags, following set applied:
     - 'mrrANDnic_intel-x710AND1t1cAND64bANDip4base'
     - 'mrrANDnic_intel-x710AND1t1cAND78bANDip6base'
     - 'mrrANDnic_intel-x710AND1t1cAND64bANDl2bdbase'

Examples
  input: 'perftest'
    expanded: 'mrrANDnic_intel_x710-da2AND1t1cAND64bANDl2bdbase mrrANDnic_intel_x710-da2AND1t1cAND64bANDip4base mrrANDnic_intel_x710-da2AND1t1cAND78bANDip6base'
  input: 'perftest l2bdbase l2xcbase'
    expanded: 'mrrANDnic_intel_x710-da2ANDl2bdbase mrrANDnic_intel_x710-da2ANDl2xcbase'
  input: 'perftest ip4base !feature'
    expanded: 'mrrANDnic_intel_x710-da2ANDip4base' not 'feature'
  input: 'perftest ip4base !feature !lbond_dpdk'
    expanded: 'mrrANDnic_intel_x710-da2ANDip4base' not 'feature' not 'lbond_dpdk'
  input: 'perftestxyx ip4base !feature !lbond_dpdk'
    invalid: detected as error
  input: 'perftestip4base !feature !lbond_dpdk'
    invalid: detected as error
  input: 'perftest ip4base!feature!lbond_dpdk'
    invalid expand: 'mrrANDnic_intel_x710-da2ANDip4base!feature!lbond_dpdk'
    execution of RobotFramework will fail

Constrains
  Trigger keyword must be different for every job to avoid running multiple jobs
  at once. Trigger keyword must not be substring of job name or any other
  message printed by JJB bach to gerrit message which can lead to recursive
  execution.

Implementation
--------------

Implementation is separated into two projects.

CI-MANGEMENT
~~~~~~~~~~~~

https://gerrit.fd.io/r/#/c/13027/

Implementing new gerrit keyword `csit-perftest` in JJB for
*csit-vpp-perf-verify-{stream}* and `perftest` for
*vpp-csit-verify-hw-perf-{stream}* performance jobs.

::

  if [[ ${GERRIT_EVENT_TYPE} == 'comment-added' ]]; then
      TRIGGER=`echo ${GERRIT_EVENT_COMMENT_TEXT} \
          | grep -oE '(perftest$|perftest[[:space:]].+$)'`
  else
      TRIGGER=''
  fi
  # Export test type
  export TEST_TAG="VERIFY-PERF-PATCH"
  # Export test tags as string
  export TEST_TAG_STRING=${TRIGGER#$"perftest"}

Code is automatically detecting trigger type and parse the gerrit comment
massage. Stripped TAGs are exported as bash variable `$TEST_TAG_STRING` together
with `$TEST_TAG`.

CSIT
~~~~

https://gerrit.fd.io/r/#/c/13025/

Implementing `$TEST_TAG_STRING` variable post processing. String of TAGs is
automatically converted into array to be able to loop the items. If variable is
empty default set of TAGs is applied.

Array is then converted into Robot Framework parameter notation where every word
means new `--include` parameter. Having multiple words (multiple includes) means
logical OR in selection of test cases and could be applied to add additional
test cases that have no common more specific match. See exmaples section for
more details. Script also detects an exclamation mark before TAG that is
translated to as a `--exclude` parameter.

References
----------

.. [1] https://wiki.fd.io/view/CSIT/Jobs
.. [2] https://git.fd.io/ci-management/tree/jjb/vpp/vpp.yaml#n762
.. [3] https://git.fd.io/csit/tree/bootstrap-verify-perf.sh#n235
.. [4] https://git.fd.io/csit/tree/docs/tag_documentation.rst
an> socket_id = clib_net_to_host_u32 (mp->socket_id); if (socket_id == 0 || socket_id == ~0) { rv = VNET_API_ERROR_INVALID_ARGUMENT; goto reply; } /* socket filename */ socket_filename = 0; mp->socket_filename[ARRAY_LEN (mp->socket_filename) - 1] = 0; len = strlen ((char *) mp->socket_filename); if (len > 0) { vec_validate (socket_filename, len); memcpy (socket_filename, mp->socket_filename, len); } rv = memif_socket_filename_add_del (is_add, socket_id, socket_filename); vec_free (socket_filename); reply: REPLY_MACRO (VL_API_MEMIF_SOCKET_FILENAME_ADD_DEL_REPLY); } /** * @brief Message handler for memif_create API. * @param mp vl_api_memif_create_t * mp the api message */ void vl_api_memif_create_t_handler (vl_api_memif_create_t * mp) { memif_main_t *mm = &memif_main; vlib_main_t *vm = vlib_get_main (); vl_api_memif_create_reply_t *rmp; memif_create_if_args_t args = { 0 }; u32 ring_size = MEMIF_DEFAULT_RING_SIZE; static const u8 empty_hw_addr[6]; int rv = 0; /* id */ args.id = clib_net_to_host_u32 (mp->id); /* socket-id */ args.socket_id = clib_net_to_host_u32 (mp->socket_id); /* secret */ mp->secret[ARRAY_LEN (mp->secret) - 1] = 0; if (strlen ((char *) mp->secret) > 0) { vec_validate (args.secret, strlen ((char *) mp->secret)); strncpy ((char *) args.secret, (char *) mp->secret, vec_len (args.secret)); } /* role */ args.is_master = (mp->role == 0); /* mode */ args.mode = mp->mode; /* rx/tx queues */ if (args.is_master == 0) { args.rx_queues = MEMIF_DEFAULT_RX_QUEUES; args.tx_queues = MEMIF_DEFAULT_TX_QUEUES; if (mp->rx_queues) { args.rx_queues = mp->rx_queues; } if (mp->tx_queues) { args.tx_queues = mp->tx_queues; } } /* ring size */ if (mp->ring_size) { ring_size = ntohl (mp->ring_size); } if (!is_pow2 (ring_size)) { rv = VNET_API_ERROR_INVALID_ARGUMENT; goto reply; } args.log2_ring_size = min_log2 (ring_size); /* buffer size */ args.buffer_size = MEMIF_DEFAULT_BUFFER_SIZE; if (mp->buffer_size) { args.buffer_size = ntohs (mp->buffer_size); } /* MAC address */ if (memcmp (mp->hw_addr, empty_hw_addr, 6) != 0) { memcpy (args.hw_addr, mp->hw_addr, 6); args.hw_addr_set = 1; } rv = memif_create_if (vm, &args); vec_free (args.secret); reply: /* *INDENT-OFF* */ REPLY_MACRO2 (VL_API_MEMIF_CREATE_REPLY, ({ rmp->sw_if_index = htonl (args.sw_if_index); })); /* *INDENT-ON* */ } /** * @brief Message handler for memif_delete API. * @param mp vl_api_memif_delete_t * mp the api message */ void vl_api_memif_delete_t_handler (vl_api_memif_delete_t * mp) { memif_main_t *mm = &memif_main; vlib_main_t *vm = vlib_get_main (); vnet_main_t *vnm = vnet_get_main (); vl_api_memif_delete_reply_t *rmp; vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, ntohl (mp->sw_if_index)); memif_if_t *mif; int rv = 0; if (hi == NULL || memif_device_class.index != hi->dev_class_index) rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; else { mif = pool_elt_at_index (mm->interfaces, hi->dev_instance); rv = memif_delete_if (vm, mif); } REPLY_MACRO (VL_API_MEMIF_DELETE_REPLY); } static void send_memif_details (vl_api_registration_t * reg, memif_if_t * mif, vnet_sw_interface_t * swif, u8 * interface_name, u32 context) { vl_api_memif_details_t *mp; vnet_main_t *vnm = vnet_get_main (); memif_main_t *mm = &memif_main; vnet_hw_interface_t *hwif; memif_socket_file_t *msf; hwif = vnet_get_sup_hw_interface (vnm, swif->sw_if_index); mp = vl_msg_api_alloc (sizeof (*mp)); clib_memset (mp, 0, sizeof (*mp)); mp->_vl_msg_id = htons (VL_API_MEMIF_DETAILS + mm->msg_id_base); mp->context = context; mp->sw_if_index = htonl (swif->sw_if_index); strncpy ((char *) mp->if_name, (char *) interface_name, ARRAY_LEN (mp->if_name) - 1); if (hwif->hw_address) { memcpy (mp->hw_addr, hwif->hw_address, ARRAY_LEN (mp->hw_addr)); } mp->id = clib_host_to_net_u32 (mif->id); msf = pool_elt_at_index (mm->socket_files, mif->socket_file_index); mp->socket_id = clib_host_to_net_u32 (msf->socket_id); mp->role = (mif->flags & MEMIF_IF_FLAG_IS_SLAVE) ? 1 : 0; mp->ring_size = htonl (1 << mif->run.log2_ring_size); mp->buffer_size = htons (mif->run.buffer_size); mp->admin_up_down = (swif->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ? 1 : 0; mp->link_up_down = (hwif->flags & VNET_HW_INTERFACE_FLAG_LINK_UP) ? 1 : 0; vl_api_send_msg (reg, (u8 *) mp); } /** * @brief Message handler for memif_dump API. * @param mp vl_api_memif_dump_t * mp the api message */ void vl_api_memif_dump_t_handler (vl_api_memif_dump_t * mp) { memif_main_t *mm = &memif_main; vnet_main_t *vnm = vnet_get_main (); vnet_sw_interface_t *swif; memif_if_t *mif; u8 *if_name = 0; vl_api_registration_t *reg; reg = vl_api_client_index_to_registration (mp->client_index); if (!reg) return; /* *INDENT-OFF* */ pool_foreach (mif, mm->interfaces, ({ swif = vnet_get_sw_interface (vnm, mif->sw_if_index); if_name = format (if_name, "%U%c", format_vnet_sw_interface_name, vnm, swif, 0); send_memif_details (reg, mif, swif, if_name, mp->context); _vec_len (if_name) = 0; })); /* *INDENT-ON* */ vec_free (if_name); } static void send_memif_socket_filename_details (vl_api_registration_t * reg, u32 socket_id, u8 * socket_filename, u32 context) { vl_api_memif_socket_filename_details_t *mp; memif_main_t *mm = &memif_main; mp = vl_msg_api_alloc (sizeof (*mp)); clib_memset (mp, 0, sizeof (*mp)); mp->_vl_msg_id = htons (VL_API_MEMIF_SOCKET_FILENAME_DETAILS + mm->msg_id_base); mp->context = context; mp->socket_id = clib_host_to_net_u32 (socket_id); strncpy ((char *) mp->socket_filename, (char *) socket_filename, ARRAY_LEN (mp->socket_filename) - 1); vl_api_send_msg (reg, (u8 *) mp); } /** * @brief Message handler for memif_socket_filename_dump API. * @param mp vl_api_memif_socket_filename_dump_t api message */ void vl_api_memif_socket_filename_dump_t_handler (vl_api_memif_socket_filename_dump_t * mp) { memif_main_t *mm = &memif_main; vl_api_registration_t *reg; u32 sock_id; u32 msf_idx; reg = vl_api_client_index_to_registration (mp->client_index); if (!reg) return; /* *INDENT-OFF* */ hash_foreach (sock_id, msf_idx, mm->socket_file_index_by_sock_id, ({ memif_socket_file_t *msf; u8 *filename; msf = pool_elt_at_index(mm->socket_files, msf_idx); filename = msf->filename; send_memif_socket_filename_details(reg, sock_id, filename, mp->context); })); /* *INDENT-ON* */ } #define vl_msg_name_crc_list #include <memif/memif_all_api_h.h> #undef vl_msg_name_crc_list static void setup_message_id_table (memif_main_t * mm, api_main_t * am) { #define _(id,n,crc) \ vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + mm->msg_id_base); foreach_vl_msg_name_crc_memif; #undef _ } /* Set up the API message handling tables */ clib_error_t * memif_plugin_api_hookup (vlib_main_t * vm) { memif_main_t *mm = &memif_main; api_main_t *am = &api_main; u8 *name; /* Construct the API name */ name = format (0, "memif_%08x%c", api_version, 0); /* Ask for a correctly-sized block of API message decode slots */ mm->msg_id_base = vl_msg_api_get_msg_ids ((char *) name, VL_MSG_FIRST_AVAILABLE); #define _(N,n) \ vl_msg_api_set_handlers((VL_API_##N + mm->msg_id_base), \ #n, \ vl_api_##n##_t_handler, \ vl_noop_handler, \ vl_api_##n##_t_endian, \ vl_api_##n##_t_print, \ sizeof(vl_api_##n##_t), 1); foreach_memif_plugin_api_msg; #undef _ /* * Set up the (msg_name, crc, message-id) table */ setup_message_id_table (mm, am); vec_free (name); return 0; } /* * fd.io coding-style-patch-verification: ON * * Local Variables: * eval: (c-set-style "gnu") * End: */