LCOV - code coverage report
Current view: top level - vppinfra/vector - ip_csum.h (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 92 172 53.5 %
Date: 2023-07-05 22:20:52 Functions: 9 11 81.8 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: Apache-2.0
       2             :  * Copyright(c) 2021 Cisco Systems, Inc.
       3             :  */
       4             : 
       5             : #ifndef included_vector_ip_csum_h
       6             : #define included_vector_ip_csum_h
       7             : #include <vppinfra/clib.h>
       8             : typedef struct
       9             : {
      10             :   u64 sum;
      11             :   u8 odd;
      12             : } clib_ip_csum_t;
      13             : 
      14             : #if defined(CLIB_HAVE_VEC128)
      15             : static_always_inline u64x2
      16   615865000 : clib_ip_csum_cvt_and_add_4 (u32x4 v)
      17             : {
      18  1231730000 :   return ((u64x2) u32x4_interleave_lo ((u32x4) v, u32x4_zero ()) +
      19   615865000 :           (u64x2) u32x4_interleave_hi ((u32x4) v, u32x4_zero ()));
      20             : }
      21             : static_always_inline u64
      22    26592957 : clib_ip_csum_hadd_2 (u64x2 v)
      23             : {
      24    26592957 :   return v[0] + v[1];
      25             : }
      26             : #endif
      27             : 
      28             : #if defined(CLIB_HAVE_VEC256)
      29             : static_always_inline u64x4
      30    10914637 : clib_ip_csum_cvt_and_add_8 (u32x8 v)
      31             : {
      32    21829174 :   return ((u64x4) u32x8_interleave_lo ((u32x8) v, u32x8_zero ()) +
      33    10914597 :           (u64x4) u32x8_interleave_hi ((u32x8) v, u32x8_zero ()));
      34             : }
      35             : static_always_inline u64
      36    10306967 : clib_ip_csum_hadd_4 (u64x4 v)
      37             : {
      38    10306967 :   return clib_ip_csum_hadd_2 (u64x4_extract_lo (v) + u64x4_extract_hi (v));
      39             : }
      40             : #endif
      41             : 
      42             : #if defined(CLIB_HAVE_VEC512)
      43             : static_always_inline u64x8
      44           0 : clib_ip_csum_cvt_and_add_16 (u32x16 v)
      45             : {
      46           0 :   return ((u64x8) u32x16_interleave_lo ((u32x16) v, u32x16_zero ()) +
      47           0 :           (u64x8) u32x16_interleave_hi ((u32x16) v, u32x16_zero ()));
      48             : }
      49             : static_always_inline u64
      50           0 : clib_ip_csum_hadd_8 (u64x8 v)
      51             : {
      52           0 :   return clib_ip_csum_hadd_4 (u64x8_extract_lo (v) + u64x8_extract_hi (v));
      53             : }
      54             : #endif
      55             : 
      56             : static_always_inline void
      57    26593067 : clib_ip_csum_inline (clib_ip_csum_t *c, u8 *dst, u8 *src, u16 count,
      58             :                      int is_copy)
      59             : {
      60    26593067 :   if (c->odd)
      61             :     {
      62           0 :       c->odd = 0;
      63           0 :       c->sum += (u16) src[0] << 8;
      64           0 :       count--;
      65           0 :       src++;
      66           0 :       if (is_copy)
      67           0 :         dst++[0] = src[0];
      68             :     }
      69             : 
      70             : #if defined(CLIB_HAVE_VEC512)
      71           0 :   u64x8 sum8 = {};
      72             : 
      73           0 :   while (count >= 512)
      74             :     {
      75           0 :       u32x16u *s = (u32x16u *) src;
      76           0 :       sum8 += clib_ip_csum_cvt_and_add_16 (s[0]);
      77           0 :       sum8 += clib_ip_csum_cvt_and_add_16 (s[1]);
      78           0 :       sum8 += clib_ip_csum_cvt_and_add_16 (s[2]);
      79           0 :       sum8 += clib_ip_csum_cvt_and_add_16 (s[3]);
      80           0 :       sum8 += clib_ip_csum_cvt_and_add_16 (s[8]);
      81           0 :       sum8 += clib_ip_csum_cvt_and_add_16 (s[5]);
      82           0 :       sum8 += clib_ip_csum_cvt_and_add_16 (s[6]);
      83           0 :       sum8 += clib_ip_csum_cvt_and_add_16 (s[7]);
      84           0 :       count -= 512;
      85           0 :       src += 512;
      86           0 :       if (is_copy)
      87             :         {
      88           0 :           u32x16u *d = (u32x16u *) dst;
      89           0 :           d[0] = s[0];
      90           0 :           d[1] = s[1];
      91           0 :           d[2] = s[2];
      92           0 :           d[3] = s[3];
      93           0 :           d[4] = s[4];
      94           0 :           d[5] = s[5];
      95           0 :           d[6] = s[6];
      96           0 :           d[7] = s[7];
      97           0 :           dst += 512;
      98             :         }
      99             :     }
     100             : 
     101           0 :   while (count >= 64)
     102             :     {
     103           0 :       u32x16u *s = (u32x16u *) src;
     104           0 :       sum8 += clib_ip_csum_cvt_and_add_16 (s[0]);
     105           0 :       count -= 64;
     106           0 :       src += 64;
     107           0 :       if (is_copy)
     108             :         {
     109           0 :           u32x16u *d = (u32x16u *) dst;
     110           0 :           d[0] = s[0];
     111           0 :           dst += 512;
     112             :         }
     113             :     }
     114             : 
     115             : #ifdef CLIB_HAVE_VEC256_MASK_LOAD_STORE
     116           0 :   if (count)
     117             :     {
     118           0 :       u64 mask = pow2_mask (count);
     119           0 :       u32x16 v = (u32x16) u8x64_mask_load_zero (src, mask);
     120           0 :       sum8 += clib_ip_csum_cvt_and_add_16 (v);
     121           0 :       c->odd = count & 1;
     122           0 :       if (is_copy)
     123           0 :         u32x16_mask_store (v, dst, mask);
     124             :     }
     125           0 :   c->sum += clib_ip_csum_hadd_8 (sum8);
     126           0 :   return;
     127             : #endif
     128             : 
     129             :   c->sum += clib_ip_csum_hadd_8 (sum8);
     130             : #elif defined(CLIB_HAVE_VEC256)
     131    10307067 :   u64x4 sum4 = {};
     132             : 
     133    10307037 :   while (count >= 256)
     134             :     {
     135           0 :       u32x8u *s = (u32x8u *) src;
     136           0 :       sum4 += clib_ip_csum_cvt_and_add_8 (s[0]);
     137           0 :       sum4 += clib_ip_csum_cvt_and_add_8 (s[1]);
     138           0 :       sum4 += clib_ip_csum_cvt_and_add_8 (s[2]);
     139           0 :       sum4 += clib_ip_csum_cvt_and_add_8 (s[3]);
     140           0 :       sum4 += clib_ip_csum_cvt_and_add_8 (s[4]);
     141           0 :       sum4 += clib_ip_csum_cvt_and_add_8 (s[5]);
     142           0 :       sum4 += clib_ip_csum_cvt_and_add_8 (s[6]);
     143           0 :       sum4 += clib_ip_csum_cvt_and_add_8 (s[7]);
     144           0 :       count -= 256;
     145           0 :       src += 256;
     146           0 :       if (is_copy)
     147             :         {
     148           0 :           u32x8u *d = (u32x8u *) dst;
     149           0 :           d[0] = s[0];
     150           0 :           d[1] = s[1];
     151           0 :           d[2] = s[2];
     152           0 :           d[3] = s[3];
     153           0 :           d[4] = s[4];
     154           0 :           d[5] = s[5];
     155           0 :           d[6] = s[6];
     156           0 :           d[7] = s[7];
     157           0 :           dst += 256;
     158             :         }
     159             :     }
     160             : 
     161    10914637 :   while (count >= 32)
     162             :     {
     163      607600 :       u32x8u *s = (u32x8u *) src;
     164      607600 :       sum4 += clib_ip_csum_cvt_and_add_8 (s[0]);
     165      607600 :       count -= 32;
     166      607600 :       src += 32;
     167      607600 :       if (is_copy)
     168             :         {
     169           0 :           u32x8u *d = (u32x8u *) dst;
     170           0 :           d[0] = s[0];
     171           0 :           dst += 32;
     172             :         }
     173             :     }
     174             : 
     175             : #ifdef CLIB_HAVE_VEC256_MASK_LOAD_STORE
     176    10307037 :   if (count)
     177             :     {
     178    10307037 :       u32 mask = pow2_mask (count);
     179    10307037 :       u32x8 v = (u32x8) u8x32_mask_load_zero (src, mask);
     180    10307057 :       sum4 += clib_ip_csum_cvt_and_add_8 (v);
     181    10306967 :       c->odd = count & 1;
     182    10306967 :       if (is_copy)
     183           0 :         u32x8_mask_store (v, dst, mask);
     184             :     }
     185    10306967 :   c->sum += clib_ip_csum_hadd_4 (sum4);
     186    10306947 :   return;
     187             : #endif
     188             : 
     189           0 :   c->sum += clib_ip_csum_hadd_4 (sum4);
     190             : #elif defined(CLIB_HAVE_VEC128)
     191    16286000 :   u64x2 sum2 = {};
     192             : 
     193    87365000 :   while (count >= 128)
     194             :     {
     195    71079100 :       u32x4u *s = (u32x4u *) src;
     196    71079100 :       sum2 += clib_ip_csum_cvt_and_add_4 (s[0]);
     197    71079100 :       sum2 += clib_ip_csum_cvt_and_add_4 (s[1]);
     198    71079100 :       sum2 += clib_ip_csum_cvt_and_add_4 (s[2]);
     199    71079100 :       sum2 += clib_ip_csum_cvt_and_add_4 (s[3]);
     200    71079100 :       sum2 += clib_ip_csum_cvt_and_add_4 (s[4]);
     201    71079100 :       sum2 += clib_ip_csum_cvt_and_add_4 (s[5]);
     202    71079100 :       sum2 += clib_ip_csum_cvt_and_add_4 (s[6]);
     203    71079100 :       sum2 += clib_ip_csum_cvt_and_add_4 (s[7]);
     204    71079100 :       count -= 128;
     205    71079100 :       src += 128;
     206    71079100 :       if (is_copy)
     207             :         {
     208    71079100 :           u32x4u *d = (u32x4u *) dst;
     209    71079100 :           d[0] = s[0];
     210    71079100 :           d[1] = s[1];
     211    71079100 :           d[2] = s[2];
     212    71079100 :           d[3] = s[3];
     213    71079100 :           d[4] = s[4];
     214    71079100 :           d[5] = s[5];
     215    71079100 :           d[6] = s[6];
     216    71079100 :           d[7] = s[7];
     217    71079100 :           dst += 128;
     218             :         }
     219             :     }
     220             : 
     221    63517900 :   while (count >= 16)
     222             :     {
     223    47232000 :       u32x4u *s = (u32x4u *) src;
     224    47232000 :       sum2 += clib_ip_csum_cvt_and_add_4 (s[0]);
     225    47232000 :       count -= 16;
     226    47232000 :       src += 16;
     227    47232000 :       if (is_copy)
     228             :         {
     229    35505500 :           u32x4u *d = (u32x4u *) dst;
     230    35505500 :           d[0] = s[0];
     231    35505500 :           dst += 16;
     232             :         }
     233             :     }
     234    16286000 :   c->sum += clib_ip_csum_hadd_2 (sum2);
     235             : #else
     236             :   while (count >= 4)
     237             :     {
     238             :       u32 v = *((u32 *) src);
     239             :       c->sum += v;
     240             :       count -= 4;
     241             :       src += 4;
     242             :       if (is_copy)
     243             :         {
     244             :           *(u32 *) dst = v;
     245             :           dst += 4;
     246             :         }
     247             :     }
     248             : #endif
     249    57114200 :   while (count >= 2)
     250             :     {
     251    40828300 :       u16 v = *((u16 *) src);
     252    40828300 :       c->sum += v;
     253    40828300 :       count -= 2;
     254    40828300 :       src += 2;
     255    40828300 :       if (is_copy)
     256             :         {
     257    40822300 :           *(u16 *) dst = v;
     258    40822300 :           dst += 2;
     259             :         }
     260             :     }
     261             : 
     262    16286000 :   if (count)
     263             :     {
     264       35496 :       c->odd = 1;
     265       35496 :       c->sum += (u16) src[0];
     266       35496 :       if (is_copy)
     267       35496 :         dst[0] = src[0];
     268             :     }
     269    16286000 : }
     270             : 
     271             : static_always_inline u16
     272    16171697 : clib_ip_csum_fold (clib_ip_csum_t *c)
     273             : {
     274    16171697 :   u64 sum = c->sum;
     275             : #if defined(__x86_64__) && defined(__BMI2__)
     276    10306947 :   u64 tmp = sum;
     277    10306947 :   asm volatile(
     278             :     /* using ADC is much faster than mov, shift, add sequence
     279             :      * compiler produces */
     280             :     "shr   $32, %[sum]                     \n\t"
     281             :     "add   %k[tmp], %k[sum]                \n\t"
     282             :     "mov   $16, %k[tmp]                    \n\t"
     283             :     "shrx  %k[tmp], %k[sum], %k[tmp]       \n\t"
     284             :     "adc   %w[tmp], %w[sum]                \n\t"
     285             :     "adc   $0, %w[sum]                     \n\t"
     286             :     : [ sum ] "+&r"(sum), [ tmp ] "+&r"(tmp));
     287             : #else
     288     5864750 :   sum = ((u32) sum) + (sum >> 32);
     289     5864750 :   sum = ((u16) sum) + (sum >> 16);
     290     5864750 :   sum = ((u16) sum) + (sum >> 16);
     291             : #endif
     292    16171717 :   return (~((u16) sum));
     293             : }
     294             : 
     295             : static_always_inline void
     296     5864750 : clib_ip_csum_chunk (clib_ip_csum_t *c, u8 *src, u16 count)
     297             : {
     298     5864750 :   return clib_ip_csum_inline (c, 0, src, count, 0);
     299             : }
     300             : 
     301             : static_always_inline void
     302    10421200 : clib_ip_csum_and_copy_chunk (clib_ip_csum_t *c, u8 *src, u8 *dst, u16 count)
     303             : {
     304    10421200 :   return clib_ip_csum_inline (c, dst, src, count, 1);
     305             : }
     306             : 
     307             : static_always_inline u16
     308    10307007 : clib_ip_csum (u8 *src, u16 count)
     309             : {
     310    10307007 :   clib_ip_csum_t c = {};
     311             :   if (COMPILE_TIME_CONST (count) && count == 12)
     312             :     {
     313             :       for (int i = 0; i < 3; i++)
     314             :         c.sum += ((u32 *) src)[i];
     315             :     }
     316             :   else if (COMPILE_TIME_CONST (count) && count == 20)
     317             :     {
     318             :       for (int i = 0; i < 5; i++)
     319             :         c.sum += ((u32 *) src)[i];
     320             :     }
     321             :   else if (COMPILE_TIME_CONST (count) && count == 40)
     322             :     {
     323             :       for (int i = 0; i < 10; i++)
     324             :         c.sum += ((u32 *) src)[i];
     325             :     }
     326             :   else
     327    10307007 :     clib_ip_csum_inline (&c, 0, src, count, 0);
     328    10306947 :   return clib_ip_csum_fold (&c);
     329             : }
     330             : 
     331             : static_always_inline u16
     332             : clib_ip_csum_and_copy (u8 *dst, u8 *src, u16 count)
     333             : {
     334             :   clib_ip_csum_t c = {};
     335             :   clib_ip_csum_inline (&c, dst, src, count, 1);
     336             :   return clib_ip_csum_fold (&c);
     337             : }
     338             : 
     339             : #endif

Generated by: LCOV version 1.14