X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvppinfra%2Fvec.h;h=9054eaa5e5778b27420d4786aad3de4b8c4dc9eb;hb=a690fdbfe179e0ea65818c03b52535bf9210efd0;hp=1b0378fe063d64a23d4ddf395fce14773861c4fc;hpb=947ea6222dad1ef04595c34273e9231395aef443;p=vpp.git diff --git a/src/vppinfra/vec.h b/src/vppinfra/vec.h index 1b0378fe063..9054eaa5e57 100644 --- a/src/vppinfra/vec.h +++ b/src/vppinfra/vec.h @@ -70,16 +70,18 @@ Typically, the header is not present. Headers allow for other data structures to be built atop CLIB vectors. - Users may specify the alignment for data elements via the - vec_*_aligned macros. + Users may specify the alignment for first data element of a vector + via the vec_*_aligned macros. - Vectors elements can be any C type e.g. (int, double, struct bar). + Vector elements can be any C type e.g. (int, double, struct bar). This is also true for data types built atop vectors (e.g. heap, pool, etc.). - Many macros have _a variants supporting alignment of vector data - and _h variants supporting non zero length vector headers. - The _ha variants support both. + Many macros have \_a variants supporting alignment of vector elements + and \_h variants supporting non-zero-length vector headers. The \_ha + variants support both. Additionally cacheline alignment within a + vector element structure can be specified using the + CLIB_CACHE_LINE_ALIGN_MARK() macro. Standard programming error: memorize a pointer to the ith element of a vector then expand it. Vectors expand by 3/2, so such code @@ -94,12 +96,14 @@ @param data_bytes requested size in bytes @param header_bytes header size in bytes (may be zero) @param data_align alignment (may be zero) + @param numa_id numa id (may be zero) @return v_prime pointer to resized vector, may or may not equal v */ void *vec_resize_allocate_memory (void *v, word length_increment, uword data_bytes, - uword header_bytes, uword data_align); + uword header_bytes, uword data_align, + uword numa_id); /** \brief Low-level vector resize function, usually not called directly @@ -108,19 +112,25 @@ void *vec_resize_allocate_memory (void *v, @param data_bytes requested size in bytes @param header_bytes header size in bytes (may be zero) @param data_align alignment (may be zero) + @param numa_id (may be ~0) @return v_prime pointer to resized vector, may or may not equal v */ -#define _vec_resize(V,L,DB,HB,A) \ - _vec_resize_inline(V,L,DB,HB,clib_max((__alignof__((V)[0])),(A))) +#define _vec_resize_numa(V,L,DB,HB,A,S) \ + _vec_resize_inline(V,L,DB,HB,clib_max((__alignof__((V)[0])),(A)),(S)) + +#define _vec_resize(V,L,DB,HB,A) \ + _vec_resize_numa(V,L,DB,HB,A,VEC_NUMA_UNSPECIFIED) always_inline void * _vec_resize_inline (void *v, word length_increment, - uword data_bytes, uword header_bytes, uword data_align) + uword data_bytes, uword header_bytes, uword data_align, + uword numa_id) { vec_header_t *vh = _vec_find (v); uword new_data_bytes, aligned_header_bytes; + void *oldheap; aligned_header_bytes = vec_header_bytes (header_bytes); @@ -130,22 +140,33 @@ _vec_resize_inline (void *v, { void *p = v - aligned_header_bytes; + if (PREDICT_FALSE (numa_id != VEC_NUMA_UNSPECIFIED)) + { + oldheap = clib_mem_get_per_cpu_heap (); + clib_mem_set_per_cpu_heap (clib_mem_get_per_numa_heap (numa_id)); + } + /* Vector header must start heap object. */ ASSERT (clib_mem_is_heap_object (p)); /* Typically we'll not need to resize. */ if (new_data_bytes <= clib_mem_size (p)) { + CLIB_MEM_UNPOISON (v, data_bytes); vh->len += length_increment; + if (PREDICT_FALSE (numa_id != VEC_NUMA_UNSPECIFIED)) + clib_mem_set_per_cpu_heap (oldheap); return v; } + if (PREDICT_FALSE (numa_id != VEC_NUMA_UNSPECIFIED)) + clib_mem_set_per_cpu_heap (oldheap); } /* Slow path: call helper function. */ return vec_resize_allocate_memory (v, length_increment, data_bytes, header_bytes, clib_max (sizeof (vec_header_t), - data_align)); + data_align), numa_id); } /** \brief Determine if vector will resize with next allocation @@ -218,16 +239,32 @@ clib_mem_is_vec (void *v) @param N number of elements to add @param H header size in bytes (may be zero) @param A alignment (may be zero) + @param S numa_id (may be zero) @return V (value-result macro parameter) */ -#define vec_resize_ha(V,N,H,A) \ -do { \ - word _v(n) = (N); \ - word _v(l) = vec_len (V); \ - V = _vec_resize ((V), _v(n), (_v(l) + _v(n)) * sizeof ((V)[0]), (H), (A)); \ +#define vec_resize_has(V,N,H,A,S) \ +do { \ + word _v(n) = (N); \ + word _v(l) = vec_len (V); \ + V = _vec_resize_numa ((V), _v(n), \ + (_v(l) + _v(n)) * sizeof ((V)[0]), \ + (H), (A),(S)); \ } while (0) +/** \brief Resize a vector (less general version). + Add N elements to end of given vector V, return pointer to start of vector. + Vector will have room for H header bytes and will have user's data aligned + at alignment A (rounded to next power of 2). + + @param V pointer to a vector + @param N number of elements to add + @param H header size in bytes (may be zero) + @param A alignment (may be zero) + @return V (value-result macro parameter) +*/ +#define vec_resize_ha(V,N,H,A) vec_resize_has(V,N,H,A,VEC_NUMA_UNSPECIFIED) + /** \brief Resize a vector (no header, unspecified alignment) Add N elements to end of given vector V, return pointer to start of vector. Vector will have room for H header bytes and will have user's data aligned @@ -349,22 +386,35 @@ do { \ @param V pointer to a vector @param H size of header in bytes @param A alignment (may be zero) + @param S numa (may be VEC_NUMA_UNSPECIFIED) @return Vdup copy of vector */ -#define vec_dup_ha(V,H,A) \ +#define vec_dup_ha_numa(V,H,A,S) \ ({ \ __typeof__ ((V)[0]) * _v(v) = 0; \ uword _v(l) = vec_len (V); \ if (_v(l) > 0) \ { \ - vec_resize_ha (_v(v), _v(l), (H), (A)); \ - clib_memcpy (_v(v), (V), _v(l) * sizeof ((V)[0]));\ + vec_resize_has (_v(v), _v(l), (H), (A), (S)); \ + clib_memcpy_fast (_v(v), (V), _v(l) * sizeof ((V)[0]));\ } \ _v(v); \ }) +/** \brief Return copy of vector (VEC_NUMA_UNSPECIFIED). + + @param V pointer to a vector + @param H size of header in bytes + @param A alignment (may be zero) + + @return Vdup copy of vector +*/ +#define vec_dup_ha(V,H,A) \ + vec_dup_ha_numa(V,H,A,VEC_NUMA_UNSPECIFIED) + + /** \brief Return copy of vector (no header, no alignment) @param V pointer to a vector @@ -387,7 +437,7 @@ do { \ @param DST destination @param SRC source */ -#define vec_copy(DST,SRC) clib_memcpy (DST, SRC, vec_len (DST) * \ +#define vec_copy(DST,SRC) clib_memcpy_fast (DST, SRC, vec_len (DST) * \ sizeof ((DST)[0])) /** \brief Clone a vector. Make a new vector with the @@ -409,24 +459,40 @@ do { \ @param I vector index which will be valid upon return @param H header size in bytes (may be zero) @param A alignment (may be zero) + @param N numa_id (may be zero) @return V (value-result macro parameter) */ -#define vec_validate_ha(V,I,H,A) \ -do { \ - STATIC_ASSERT(A==0 || ((A % sizeof(V[0]))==0) || ((sizeof(V[0]) % A) == 0),\ - "vector validate aligned on incorrectly sized object"); \ - word _v(i) = (I); \ - word _v(l) = vec_len (V); \ - if (_v(i) >= _v(l)) \ - { \ - vec_resize_ha ((V), 1 + (_v(i) - _v(l)), (H), (A)); \ - /* Must zero new space since user may have previously \ - used e.g. _vec_len (v) -= 10 */ \ - memset ((V) + _v(l), 0, (1 + (_v(i) - _v(l))) * sizeof ((V)[0])); \ - } \ +#define vec_validate_han(V,I,H,A,N) \ +do { \ + void *oldheap; \ + STATIC_ASSERT(A==0 || ((A % sizeof(V[0]))==0) \ + || ((sizeof(V[0]) % A) == 0), \ + "vector validate aligned on incorrectly sized object"); \ + word _v(i) = (I); \ + word _v(l) = vec_len (V); \ + if (_v(i) >= _v(l)) \ + { \ + /* switch to the per-numa heap if directed */ \ + if (PREDICT_FALSE(N != VEC_NUMA_UNSPECIFIED)) \ + { \ + oldheap = clib_mem_get_per_cpu_heap(); \ + clib_mem_set_per_cpu_heap (clib_mem_get_per_numa_heap(N)); \ + } \ + \ + vec_resize_ha ((V), 1 + (_v(i) - _v(l)), (H), (A)); \ + /* Must zero new space since user may have previously \ + used e.g. _vec_len (v) -= 10 */ \ + clib_memset ((V) + _v(l), 0, \ + (1 + (_v(i) - _v(l))) * sizeof ((V)[0])); \ + /* Switch back to the global heap */ \ + if (PREDICT_FALSE (N != VEC_NUMA_UNSPECIFIED)) \ + clib_mem_set_per_cpu_heap (oldheap); \ + } \ } while (0) +#define vec_validate_ha(V,I,H,A) vec_validate_han(V,I,H,A,VEC_NUMA_UNSPECIFIED) + /** \brief Make sure vector is long enough for given index (no header, unspecified alignment) @@ -478,8 +544,6 @@ do { \ @param V (possibly NULL) pointer to a vector. @param I vector index which will be valid upon return @param INIT initial value (can be a complex expression!) - @param H header size in bytes (may be zero) - @param A alignment (may be zero) @return V (value-result macro parameter) */ @@ -492,7 +556,6 @@ do { \ @param V (possibly NULL) pointer to a vector. @param I vector index which will be valid upon return @param INIT initial value (can be a complex expression!) - @param H header size in bytes (may be zero) @param A alignment (may be zero) @return V (value-result macro parameter) */ @@ -526,7 +589,6 @@ do { \ @param V pointer to a vector @param E element to add - @param H header size in bytes (may be zero) @param A alignment (may be zero) @return V (value-result macro parameter) */ @@ -587,7 +649,7 @@ do { \ word _v(n) = (N); \ word _v(l) = vec_len (V); \ V = _vec_resize ((V), _v(n), (_v(l) + _v(n)) * sizeof ((V)[0]), (H), (A)); \ - clib_memcpy ((V) + _v(l), (E), _v(n) * sizeof ((V)[0])); \ + clib_memcpy_fast ((V) + _v(l), (E), _v(n) * sizeof ((V)[0])); \ } while (0) /** \brief Add N elements to end of vector V (no header, unspecified alignment) @@ -661,7 +723,7 @@ do { \ memmove ((V) + _v(m) + _v(n), \ (V) + _v(m), \ (_v(l) - _v(m)) * sizeof ((V)[0])); \ - memset ((V) + _v(m), INIT, _v(n) * sizeof ((V)[0])); \ + clib_memset ((V) + _v(m), INIT, _v(n) * sizeof ((V)[0])); \ } while (0) /** \brief Insert N vector elements starting at element M, @@ -749,7 +811,7 @@ do { \ memmove ((V) + _v(m) + _v(n), \ (V) + _v(m), \ (_v(l) - _v(m)) * sizeof ((V)[0])); \ - clib_memcpy ((V) + _v(m), (E), \ + clib_memcpy_fast ((V) + _v(m), (E), \ _v(n) * sizeof ((V)[0])); \ } while (0) @@ -794,8 +856,9 @@ do { \ (_v(l) - _v(n) - _v(m)) * sizeof ((V)[0])); \ /* Zero empty space at end (for future re-allocation). */ \ if (_v(n) > 0) \ - memset ((V) + _v(l) - _v(n), 0, _v(n) * sizeof ((V)[0])); \ + clib_memset ((V) + _v(l) - _v(n), 0, _v(n) * sizeof ((V)[0])); \ _vec_len (V) -= _v(n); \ + CLIB_MEM_POISON(vec_end(V), _v(n) * sizeof ((V)[0])); \ } while (0) /** \brief Delete the element at index I @@ -810,6 +873,7 @@ do { \ if (_vec_del_i < _vec_del_l) \ (v)[_vec_del_i] = (v)[_vec_del_l]; \ _vec_len (v) = _vec_del_l; \ + CLIB_MEM_POISON(vec_end(v), sizeof ((v)[0])); \ } while (0) /** \brief Append v2 after v1. Result in v1. @@ -824,7 +888,7 @@ do { \ \ v1 = _vec_resize ((v1), _v(l2), \ (_v(l1) + _v(l2)) * sizeof ((v1)[0]), 0, 0); \ - clib_memcpy ((v1) + _v(l1), (v2), _v(l2) * sizeof ((v2)[0])); \ + clib_memcpy_fast ((v1) + _v(l1), (v2), _v(l2) * sizeof ((v2)[0])); \ } while (0) /** \brief Append v2 after v1. Result in v1. Specified alignment. @@ -840,7 +904,7 @@ do { \ \ v1 = _vec_resize ((v1), _v(l2), \ (_v(l1) + _v(l2)) * sizeof ((v1)[0]), 0, align); \ - clib_memcpy ((v1) + _v(l1), (v2), _v(l2) * sizeof ((v2)[0])); \ + clib_memcpy_fast ((v1) + _v(l1), (v2), _v(l2) * sizeof ((v2)[0])); \ } while (0) /** \brief Prepend v2 before v1. Result in v1. @@ -856,7 +920,7 @@ do { \ v1 = _vec_resize ((v1), _v(l2), \ (_v(l1) + _v(l2)) * sizeof ((v1)[0]), 0, 0); \ memmove ((v1) + _v(l2), (v1), _v(l1) * sizeof ((v1)[0])); \ - clib_memcpy ((v1), (v2), _v(l2) * sizeof ((v2)[0])); \ + clib_memcpy_fast ((v1), (v2), _v(l2) * sizeof ((v2)[0])); \ } while (0) /** \brief Prepend v2 before v1. Result in v1. Specified alignment @@ -873,7 +937,7 @@ do { \ v1 = _vec_resize ((v1), _v(l2), \ (_v(l1) + _v(l2)) * sizeof ((v1)[0]), 0, align); \ memmove ((v1) + _v(l2), (v1), _v(l1) * sizeof ((v1)[0])); \ - clib_memcpy ((v1), (v2), _v(l2) * sizeof ((v2)[0])); \ + clib_memcpy_fast ((v1), (v2), _v(l2) * sizeof ((v2)[0])); \ } while (0) @@ -883,7 +947,7 @@ do { \ #define vec_zero(var) \ do { \ if (var) \ - memset ((var), 0, vec_len (var) * sizeof ((var)[0])); \ + clib_memset ((var), 0, vec_len (var) * sizeof ((var)[0])); \ } while (0) /** \brief Set all vector elements to given value. Null-pointer tolerant. @@ -935,8 +999,8 @@ do { \ /** \brief Search a vector for the index of the entry that matches. - @param v1 Pointer to a vector - @param v2 Entry to match + @param v Pointer to a vector + @param E Entry to match @return index of match or ~0 */ #define vec_search(v,E) \ @@ -955,8 +1019,8 @@ do { \ /** \brief Search a vector for the index of the entry that matches. - @param v1 Pointer to a vector - @param v2 Pointer to entry to match + @param v Pointer to a vector + @param E Pointer to entry to match @param fn Comparison function !0 => match @return index of match or ~0 */ @@ -995,7 +1059,7 @@ do { \ vec_reset_length (V); \ vec_validate ((V), (L)); \ if ((S) && (L)) \ - clib_memcpy ((V), (S), (L)); \ + clib_memcpy_fast ((V), (S), (L)); \ (V)[(L)] = 0; \ } while (0)