FD.io VPP  v16.06
Vector Packet Processing
zvec.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /*
16  Copyright (c) 2001, 2002, 2003, 2005 Eliot Dresselhaus
17 
18  Permission is hereby granted, free of charge, to any person obtaining
19  a copy of this software and associated documentation files (the
20  "Software"), to deal in the Software without restriction, including
21  without limitation the rights to use, copy, modify, merge, publish,
22  distribute, sublicense, and/or sell copies of the Software, and to
23  permit persons to whom the Software is furnished to do so, subject to
24  the following conditions:
25 
26  The above copyright notice and this permission notice shall be
27  included in all copies or substantial portions of the Software.
28 
29  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 */
37 
38 #include <vppinfra/bitmap.h>
39 #include <vppinfra/bitops.h> /* for next_with_same_number_of_set_bits */
40 #include <vppinfra/error.h> /* for ASSERT */
41 #include <vppinfra/mem.h>
42 #include <vppinfra/os.h> /* for os_panic */
43 #include <vppinfra/vec.h>
44 #include <vppinfra/zvec.h>
45 
46 /* Consider coding as bitmap, coding = 2^c_0 + 2^c_1 + ... + 2^c_n
47  With c_0 < c_1 < ... < c_n. coding == 0 represents c_n = BITS (uword).
48 
49  Unsigned integers i = 0 ... are represented as follows:
50 
51  0 <= i < 2^c_0 (i << 1) | (1 << 0) binary: i 1
52  2^c_0 <= i < 2^c_0 + 2^c_1 (i << 2) | (1 << 1) binary: i 1 0
53  ... binary: i 0 ... 0
54 
55  Smaller numbers use less bits. Coding is chosen so that encoding
56  of given histogram of typical values gives smallest number of bits.
57  The number and position of coding bits c_i are used to best fit the
58  histogram of typical values.
59 */
60 
61 /* Decode given compressed data. Return number of compressed data
62  bits used. */
63 uword zvec_decode (uword coding, uword zdata, uword * n_zdata_bits)
64 {
65  uword c, d, result, n_bits;
66  uword explicit_end, implicit_end;
67 
68  result = 0;
69  n_bits = 0;
70  while (1)
71  {
72  c = first_set (coding);
73  implicit_end = c == coding;
74  explicit_end = (zdata & 1) &~ implicit_end;
75  d = (zdata >> explicit_end) & (c - 1);
76  if (explicit_end | implicit_end)
77  {
78  result += d;
79  n_bits += min_log2 (c) + explicit_end;
80  break;
81  }
82  n_bits += 1;
83  result += c;
84  coding ^= c;
85  zdata >>= 1;
86  }
87 
88  if (coding == 0)
89  n_bits = BITS (uword);
90 
91  *n_zdata_bits = n_bits;
92  return result;
93 }
94 
95 uword
97  uword data,
98  uword * n_result_bits)
99 {
100  uword c, shift, result;
101  uword explicit_end, implicit_end;
102 
103  /* Data must be in range. Note special coding == 0
104  would break for data - 1 <= coding. */
105  ASSERT (data <= coding - 1);
106 
107  shift = 0;
108  while (1)
109  {
110  c = first_set (coding);
111  implicit_end = c == coding;
112  explicit_end = ((data & (c - 1)) == data);
113  if (explicit_end | implicit_end)
114  {
115  uword t = explicit_end &~ implicit_end;
116  result = ((data << t) | t) << shift;
117  *n_result_bits =
118  /* data bits */ (c == 0 ? BITS (uword) : min_log2 (c))
119  /* shift bits */ + shift + t;
120  return result;
121  }
122  data -= c;
123  coding ^= c;
124  shift++;
125  }
126 
127  /* Never reached. */
128  ASSERT (0);
129  return ~0;
130 }
131 
133 get_data (void * data, uword data_bytes, uword is_signed)
134 {
135  if (data_bytes == 1)
136  return is_signed ? zvec_signed_to_unsigned (*(i8 *) data) : *(u8 *) data;
137  else if (data_bytes == 2)
138  return is_signed ? zvec_signed_to_unsigned (*(i16 *) data) : *(u16 *) data;
139  else if (data_bytes == 4)
140  return is_signed ? zvec_signed_to_unsigned (*(i32 *) data) : *(u32 *) data;
141  else if (data_bytes == 8)
142  return is_signed ? zvec_signed_to_unsigned (*(i64 *) data) : *(u64 *) data;
143  else
144  {
145  os_panic ();
146  return ~0;
147  }
148 }
149 
150 always_inline void
151 put_data (void * data, uword data_bytes, uword is_signed, uword x)
152 {
153  if (data_bytes == 1)
154  {
155  if (is_signed)
156  *(i8 *) data = zvec_unsigned_to_signed (x);
157  else
158  *(u8 *) data = x;
159  }
160  else if (data_bytes == 2)
161  {
162  if (is_signed)
163  *(i16 *) data = zvec_unsigned_to_signed (x);
164  else
165  *(u16 *) data = x;
166  }
167  else if (data_bytes == 4)
168  {
169  if (is_signed)
170  *(i32 *) data = zvec_unsigned_to_signed (x);
171  else
172  *(u32 *) data = x;
173  }
174  else if (data_bytes == 8)
175  {
176  if (is_signed)
177  *(i64 *) data = zvec_unsigned_to_signed (x);
178  else
179  *(u64 *) data = x;
180  }
181  else
182  {
183  os_panic ();
184  }
185 }
186 
189  uword * zvec_n_bits,
190  uword coding,
191  void * data,
192  uword data_stride,
193  uword n_data,
194  uword data_bytes,
195  uword is_signed)
196 {
197  uword i;
198 
199  i = *zvec_n_bits;
200  while (n_data >= 1)
201  {
202  uword d0, z0, l0;
203 
204  d0 = get_data (data + 0*data_stride, data_bytes, is_signed);
205  data += 1*data_stride;
206  n_data -= 1;
207 
208  z0 = zvec_encode (coding, d0, &l0);
209  zvec = clib_bitmap_set_multiple (zvec, i, z0, l0);
210  i += l0;
211  }
212 
213  *zvec_n_bits = i;
214  return zvec;
215 }
216 
217 #define _(TYPE,IS_SIGNED) \
218  uword * zvec_encode_##TYPE (uword * zvec, \
219  uword * zvec_n_bits, \
220  uword coding, \
221  void * data, \
222  uword data_stride, \
223  uword n_data) \
224  { \
225  return zvec_encode_inline (zvec, zvec_n_bits, \
226  coding, \
227  data, data_stride, n_data, \
228  /* data_bytes */ sizeof (TYPE), \
229  /* is_signed */ IS_SIGNED); \
230  }
231 
232 _ (u8, /* is_signed */ 0);
233 _ (u16, /* is_signed */ 0);
234 _ (u32, /* is_signed */ 0);
235 _ (u64, /* is_signed */ 0);
236 _ (i8, /* is_signed */ 1);
237 _ (i16, /* is_signed */ 1);
238 _ (i32, /* is_signed */ 1);
239 _ (i64, /* is_signed */ 1);
240 
241 #undef _
242 
245 {
246  uword n_bits;
247  (void) zvec_decode (coding, 0, &n_bits);
248  return n_bits;
249 }
250 
251 always_inline void
253  uword * zvec_n_bits,
254  uword coding,
255  void * data,
256  uword data_stride,
257  uword n_data,
258  uword data_bytes,
259  uword is_signed)
260 {
261  uword i, n_max;
262 
263  i = *zvec_n_bits;
264  n_max = coding_max_n_bits (coding);
265  while (n_data >= 1)
266  {
267  uword d0, z0, l0;
268 
269  z0 = clib_bitmap_get_multiple (zvec, i, n_max);
270  d0 = zvec_decode (coding, z0, &l0);
271  i += l0;
272  put_data (data + 0*data_stride, data_bytes, is_signed, d0);
273  data += 1*data_stride;
274  n_data -= 1;
275  }
276  *zvec_n_bits = i;
277 }
278 
279 #define _(TYPE,IS_SIGNED) \
280  void zvec_decode_##TYPE (uword * zvec, \
281  uword * zvec_n_bits, \
282  uword coding, \
283  void * data, \
284  uword data_stride, \
285  uword n_data) \
286  { \
287  return zvec_decode_inline (zvec, zvec_n_bits, \
288  coding, \
289  data, data_stride, n_data, \
290  /* data_bytes */ sizeof (TYPE), \
291  /* is_signed */ IS_SIGNED); \
292  }
293 
294 _ (u8, /* is_signed */ 0);
295 _ (u16, /* is_signed */ 0);
296 _ (u32, /* is_signed */ 0);
297 _ (u64, /* is_signed */ 0);
298 _ (i8, /* is_signed */ 1);
299 _ (i16, /* is_signed */ 1);
300 _ (i32, /* is_signed */ 1);
301 _ (i64, /* is_signed */ 1);
302 
303 #undef _
304 
305 /* Compute number of bits needed to encode given histogram. */
306 static uword zvec_coding_bits (uword coding,
307  uword * histogram_counts,
308  uword min_bits)
309 {
310  uword n_type_bits, n_bits;
311  uword this_count, last_count, max_count_index;
312  uword i, b, l;
313 
314  n_bits = 0;
315  n_type_bits = 1;
316  last_count = 0;
317  max_count_index = vec_len (histogram_counts) - 1;
318 
319  /* Coding is not large enough to encode given data. */
320  if (coding <= max_count_index)
321  return ~0;
322 
323  i = 0;
324  while (coding != 0)
325  {
326  b = first_set (coding);
327  l = min_log2 (b);
328  i += b;
329 
330  this_count = histogram_counts[i > max_count_index ? max_count_index : i-1];
331 
332  /* No more data to encode? */
333  if (this_count == last_count)
334  break;
335 
336  /* Last coding is i 0 ... 0 so we don't need an extra type bit. */
337  if (coding == b)
338  n_type_bits--;
339 
340  n_bits += (this_count - last_count) * (n_type_bits + l);
341 
342  /* This coding cannot be minimal: so return. */
343  if (n_bits >= min_bits)
344  return ~0;
345 
346  last_count = this_count;
347  coding ^= b;
348  n_type_bits++;
349  }
350 
351  return n_bits;
352 }
353 
354 uword
355 _zvec_coding_from_histogram (void * histogram,
356  uword histogram_len,
357  uword histogram_elt_count_offset,
358  uword histogram_elt_bytes,
359  uword max_value_to_encode,
360  zvec_coding_info_t * coding_return)
361 {
362  uword coding, min_coding;
363  uword min_coding_bits, coding_bits;
364  uword i, n_bits_set, total_count;
365  uword * counts;
366  zvec_histogram_count_t * h_count = histogram + histogram_elt_count_offset;
367 
368  if (histogram_len < 1)
369  {
370  coding_return->coding = 0;
371  coding_return->min_coding_bits = 0;
372  coding_return->n_data = 0;
373  coding_return->n_codes = 0;
374  coding_return->ave_coding_bits = 0;
375  return 0;
376  }
377 
378  total_count = 0;
379  counts = vec_new (uword, histogram_len);
380  for (i = 0; i < histogram_len; i++)
381  {
382  zvec_histogram_count_t this_count = h_count[0];
383  total_count += this_count;
384  counts[i] = total_count;
385  h_count = (zvec_histogram_count_t *) ((void *) h_count + histogram_elt_bytes);
386  }
387 
388  min_coding = 0;
389  min_coding_bits = ~0;
390 
391  {
392  uword base_coding = max_value_to_encode != ~0 ? (1 + max_value_to_encode) : vec_len (counts);
393  uword max_coding = max_pow2 (2 * base_coding);
394 
395  for (n_bits_set = 1; n_bits_set <= 8; n_bits_set++)
396  {
397  for (coding = pow2_mask (n_bits_set);
398  coding < max_coding;
399  coding = next_with_same_number_of_set_bits (coding))
400  {
401  coding_bits = zvec_coding_bits (coding, counts, min_coding_bits);
402  if (coding_bits >= min_coding_bits)
403  continue;
404  min_coding_bits = coding_bits;
405  min_coding = coding;
406  }
407  }
408  }
409 
410  if (coding_return)
411  {
412  coding_return->coding = min_coding;
413  coding_return->min_coding_bits = min_coding_bits;
414  coding_return->n_data = total_count;
415  coding_return->n_codes = vec_len (counts);
416  coding_return->ave_coding_bits = (f64) min_coding_bits / (f64) total_count;
417  }
418 
419  vec_free (counts);
420 
421  return min_coding;
422 }
423 
424 u8 * format_zvec_coding (u8 * s, va_list * args)
425 {
426  zvec_coding_info_t * c = va_arg (*args, zvec_coding_info_t *);
427  return format (s, "zvec coding 0x%x, %d elts, %d codes, %d bits total, %.4f ave bits/code",
429 }
always_inline uword max_pow2(uword x)
Definition: clib.h:245
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:267
static void(BVT(clib_bihash)*h, BVT(clib_bihash_value)*v)
void os_panic(void)
Definition: unix-misc.c:165
always_inline void put_data(void *data, uword data_bytes, uword is_signed, uword x)
Definition: zvec.c:151
always_inline uword zvec_signed_to_unsigned(word s)
Definition: zvec.h:142
f64 ave_coding_bits
Definition: zvec.h:78
always_inline uword first_set(uword x)
Definition: clib.h:265
#define always_inline
Definition: clib.h:84
#define vec_new(T, N)
Create new vector of given type and length (unspecified alignment, no header).
Definition: vec.h:268
int i32
Definition: types.h:81
char i8
Definition: types.h:45
always_inline uword coding_max_n_bits(uword coding)
Definition: zvec.c:244
uword zvec_decode(uword coding, uword zdata, uword *n_zdata_bits)
Definition: zvec.c:63
unsigned long u64
Definition: types.h:89
uword zvec_encode(uword coding, uword data, uword *n_result_bits)
Definition: zvec.c:96
always_inline uword next_with_same_number_of_set_bits(uword x)
Definition: bitops.h:136
always_inline void zvec_decode_inline(uword *zvec, uword *zvec_n_bits, uword coding, void *data, uword data_stride, uword n_data, uword data_bytes, uword is_signed)
Definition: zvec.c:252
long i64
Definition: types.h:82
u32 zvec_histogram_count_t
Definition: zvec.h:87
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:298
always_inline uword * clib_bitmap_set_multiple(uword *bitmap, uword i, uword value, uword n_bits)
Definition: bitmap.h:226
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
always_inline uword get_data(void *data, uword data_bytes, uword is_signed)
Definition: zvec.c:133
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:405
u64 uword
Definition: types.h:112
unsigned short u16
Definition: types.h:57
always_inline uword * zvec_encode_inline(uword *zvec, uword *zvec_n_bits, uword coding, void *data, uword data_stride, uword n_data, uword data_bytes, uword is_signed)
Definition: zvec.c:188
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
double f64
Definition: types.h:140
unsigned char u8
Definition: types.h:56
static uword zvec_coding_bits(uword coding, uword *histogram_counts, uword min_bits)
Definition: zvec.c:306
short i16
Definition: types.h:46
u32 min_coding_bits
Definition: zvec.h:75
always_inline uword clib_bitmap_get_multiple(uword *bitmap, uword i, uword n_bits)
Definition: bitmap.h:192
always_inline uword min_log2(uword x)
Definition: clib.h:181
always_inline uword pow2_mask(uword x)
Definition: clib.h:242
#define BITS(x)
Definition: clib.h:58
u8 * format_zvec_coding(u8 *s, va_list *args)
Definition: zvec.c:424
always_inline word zvec_unsigned_to_signed(uword u)
Definition: zvec.h:150
CLIB vectors are ubiquitous dynamically resized arrays with by user defined "headers".