mbuf: fix performance with 128-byte cache line
[dpdk.git] / app / test / test_lpm.c
index 158d8ac..8b4ded9 100644 (file)
@@ -1,35 +1,34 @@
 /*-
  *   BSD LICENSE
- * 
- *   Copyright(c) 2010-2012 Intel Corporation. All rights reserved.
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
  *   All rights reserved.
- * 
- *   Redistribution and use in source and binary forms, with or without 
- *   modification, are permitted provided that the following conditions 
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
  *   are met:
- * 
- *     * Redistributions of source code must retain the above copyright 
+ *
+ *     * Redistributions of source code must retain the above copyright
  *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright 
- *       notice, this list of conditions and the following disclaimer in 
- *       the documentation and/or other materials provided with the 
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
  *       distribution.
- *     * Neither the name of Intel Corporation nor the names of its 
- *       contributors may be used to endorse or promote products derived 
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
  *       from this software without specific prior written permission.
- * 
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
  */
 
 #include <stdio.h>
@@ -37,7 +36,6 @@
 #include <stdlib.h>
 #include <errno.h>
 #include <sys/queue.h>
-#include <cmdline_parse.h>
 
 #include <rte_common.h>
 #include <rte_cycles.h>
 #include <rte_ip.h>
 #include <time.h>
 
-#ifdef RTE_LIBRTE_LPM
+#include "test.h"
 
 #include "rte_lpm.h"
 #include "test_lpm_routes.h"
 
-#include "test.h"
-
 #define TEST_LPM_ASSERT(cond) do {                                            \
        if (!(cond)) {                                                        \
                printf("Error at line %d: \n", __LINE__);                     \
@@ -169,7 +165,7 @@ test2(void)
 {
        struct rte_lpm *lpm = NULL;
 
-       lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, MAX_RULES, RTE_LPM_HEAP);
+       lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, MAX_RULES, 0);
        TEST_LPM_ASSERT(lpm != NULL);
 
        rte_lpm_free(lpm);
@@ -312,6 +308,8 @@ test6(void)
 int32_t
 test7(void)
 {
+       __m128i ipx4;
+       uint16_t hop[4];
        struct rte_lpm *lpm = NULL;
        uint32_t ip = IPv4(0, 0, 0, 0);
        uint8_t depth = 32, next_hop_add = 100, next_hop_return = 0;
@@ -326,6 +324,13 @@ test7(void)
        status = rte_lpm_lookup(lpm, ip, &next_hop_return);
        TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
 
+       ipx4 = _mm_set_epi32(ip, ip + 0x100, ip - 0x100, ip);
+       rte_lpm_lookupx4(lpm, ipx4, hop, UINT16_MAX);
+       TEST_LPM_ASSERT(hop[0] == next_hop_add);
+       TEST_LPM_ASSERT(hop[1] == UINT16_MAX);
+       TEST_LPM_ASSERT(hop[2] == UINT16_MAX);
+       TEST_LPM_ASSERT(hop[3] == next_hop_add);
+
        status = rte_lpm_delete(lpm, ip, depth);
        TEST_LPM_ASSERT(status == 0);
 
@@ -349,6 +354,8 @@ test7(void)
 int32_t
 test8(void)
 {
+       __m128i ipx4;
+       uint16_t hop[4];
        struct rte_lpm *lpm = NULL;
        uint32_t ip1 = IPv4(127, 255, 255, 255), ip2 = IPv4(128, 0, 0, 0);
        uint8_t depth, next_hop_add, next_hop_return;
@@ -372,6 +379,13 @@ test8(void)
                status = rte_lpm_lookup(lpm, ip2, &next_hop_return);
                TEST_LPM_ASSERT((status == 0) &&
                        (next_hop_return == next_hop_add));
+
+               ipx4 = _mm_set_epi32(ip2, ip1, ip2, ip1);
+               rte_lpm_lookupx4(lpm, ipx4, hop, UINT16_MAX);
+               TEST_LPM_ASSERT(hop[0] == UINT16_MAX);
+               TEST_LPM_ASSERT(hop[1] == next_hop_add);
+               TEST_LPM_ASSERT(hop[2] == UINT16_MAX);
+               TEST_LPM_ASSERT(hop[3] == next_hop_add);
        }
 
        /* Loop with rte_lpm_delete. */
@@ -393,6 +407,18 @@ test8(void)
 
                status = rte_lpm_lookup(lpm, ip1, &next_hop_return);
                TEST_LPM_ASSERT(status == -ENOENT);
+
+               ipx4 = _mm_set_epi32(ip1, ip1, ip2, ip2);
+               rte_lpm_lookupx4(lpm, ipx4, hop, UINT16_MAX);
+               if (depth != 1) {
+                       TEST_LPM_ASSERT(hop[0] == next_hop_add);
+                       TEST_LPM_ASSERT(hop[1] == next_hop_add);
+               } else {
+                       TEST_LPM_ASSERT(hop[0] == UINT16_MAX);
+                       TEST_LPM_ASSERT(hop[1] == UINT16_MAX);
+               }
+               TEST_LPM_ASSERT(hop[2] == UINT16_MAX);
+               TEST_LPM_ASSERT(hop[3] == UINT16_MAX);
        }
 
        rte_lpm_free(lpm);
@@ -581,7 +607,7 @@ test10(void)
 
        /* Add rule that covers a TBL24 range previously invalid & lookup
         * (& delete & lookup) */
-       lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, MAX_RULES, RTE_LPM_HEAP);
+       lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, MAX_RULES, 0);
        TEST_LPM_ASSERT(lpm != NULL);
 
        ip = IPv4(128, 0, 0, 0);
@@ -824,6 +850,8 @@ test11(void)
 int32_t
 test12(void)
 {
+       __m128i ipx4;
+       uint16_t hop[4];
        struct rte_lpm *lpm = NULL;
        uint32_t ip, i;
        uint8_t depth, next_hop_add, next_hop_return;
@@ -844,6 +872,13 @@ test12(void)
                TEST_LPM_ASSERT((status == 0) &&
                                (next_hop_return == next_hop_add));
 
+               ipx4 = _mm_set_epi32(ip, ip + 1, ip, ip - 1);
+               rte_lpm_lookupx4(lpm, ipx4, hop, UINT16_MAX);
+               TEST_LPM_ASSERT(hop[0] == UINT16_MAX);
+               TEST_LPM_ASSERT(hop[1] == next_hop_add);
+               TEST_LPM_ASSERT(hop[2] == UINT16_MAX);
+               TEST_LPM_ASSERT(hop[3] == next_hop_add);
+
                status = rte_lpm_delete(lpm, ip, depth);
                TEST_LPM_ASSERT(status == 0);
 
@@ -938,9 +973,9 @@ test14(void)
        lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, 256 * 32, 0);
        TEST_LPM_ASSERT(lpm != NULL);
 
-       ip = IPv4(0, 0, 0, 0);
        depth = 32;
        next_hop_add = 100;
+       ip = IPv4(0, 0, 0, 0);
 
        /* Add 256 rules that require a tbl8 extension */
        for (; ip <= IPv4(0, 0, 255, 0); ip += 256) {
@@ -1239,6 +1274,37 @@ perf_test(void)
                        (double)total_time / ((double)ITERATIONS * BATCH_SIZE),
                        (count * 100.0) / (double)(ITERATIONS * BATCH_SIZE));
 
+       /* Measure LookupX4 */
+       total_time = 0;
+       count = 0;
+       for (i = 0; i < ITERATIONS; i++) {
+               static uint32_t ip_batch[BATCH_SIZE];
+               uint16_t next_hops[4];
+
+               /* Create array of random IP addresses */
+               for (j = 0; j < BATCH_SIZE; j++)
+                       ip_batch[j] = rte_rand();
+
+               /* Lookup per batch */
+               begin = rte_rdtsc();
+               for (j = 0; j < BATCH_SIZE; j += RTE_DIM(next_hops)) {
+                       unsigned k;
+                       __m128i ipx4;
+
+                       ipx4 = _mm_loadu_si128((__m128i *)(ip_batch + j));
+                       ipx4 = *(__m128i *)(ip_batch + j);
+                       rte_lpm_lookupx4(lpm, ipx4, next_hops, UINT16_MAX);
+                       for (k = 0; k < RTE_DIM(next_hops); k++)
+                               if (unlikely(next_hops[k] == UINT16_MAX))
+                                       count++;
+               }
+
+               total_time += rte_rdtsc() - begin;
+       }
+       printf("LPM LookupX4: %.1f cycles (fails = %.1f%%)\n",
+                       (double)total_time / ((double)ITERATIONS * BATCH_SIZE),
+                       (count * 100.0) / (double)(ITERATIONS * BATCH_SIZE));
+
        /* Delete */
        status = 0;
        begin = rte_rdtsc();
@@ -1264,7 +1330,7 @@ perf_test(void)
  * Do all unit and performance tests.
  */
 
-int
+static int
 test_lpm(void)
 {
        unsigned i;
@@ -1281,13 +1347,8 @@ test_lpm(void)
        return global_status;
 }
 
-#else
-
-int
-test_lpm(void)
-{
-       printf("The LPM library is not included in this build\n");
-       return 0;
-}
-
-#endif
+static struct test_command lpm_cmd = {
+       .command = "lpm_autotest",
+       .callback = test_lpm,
+};
+REGISTER_TEST_COMMAND(lpm_cmd);