blob: d062e5f7db1556957de328a660afb69a55e09918 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
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>
Dave Barachc3799992016-08-15 11:12:27 -040039#include <vppinfra/bitops.h> /* for next_with_same_number_of_set_bits */
40#include <vppinfra/error.h> /* for ASSERT */
Ed Warnickecb9cada2015-12-08 15:45:58 -070041#include <vppinfra/mem.h>
Dave Barachc3799992016-08-15 11:12:27 -040042#include <vppinfra/os.h> /* for os_panic */
Ed Warnickecb9cada2015-12-08 15:45:58 -070043#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. */
Dave Barachc3799992016-08-15 11:12:27 -040063uword
64zvec_decode (uword coding, uword zdata, uword * n_zdata_bits)
Ed Warnickecb9cada2015-12-08 15:45:58 -070065{
66 uword c, d, result, n_bits;
67 uword explicit_end, implicit_end;
68
69 result = 0;
70 n_bits = 0;
71 while (1)
72 {
73 c = first_set (coding);
74 implicit_end = c == coding;
Dave Barachc3799992016-08-15 11:12:27 -040075 explicit_end = (zdata & 1) & ~implicit_end;
Ed Warnickecb9cada2015-12-08 15:45:58 -070076 d = (zdata >> explicit_end) & (c - 1);
77 if (explicit_end | implicit_end)
78 {
79 result += d;
80 n_bits += min_log2 (c) + explicit_end;
81 break;
82 }
83 n_bits += 1;
84 result += c;
85 coding ^= c;
86 zdata >>= 1;
87 }
88
89 if (coding == 0)
90 n_bits = BITS (uword);
91
92 *n_zdata_bits = n_bits;
93 return result;
94}
95
96uword
Dave Barachc3799992016-08-15 11:12:27 -040097zvec_encode (uword coding, uword data, uword * n_result_bits)
Ed Warnickecb9cada2015-12-08 15:45:58 -070098{
99 uword c, shift, result;
100 uword explicit_end, implicit_end;
101
102 /* Data must be in range. Note special coding == 0
103 would break for data - 1 <= coding. */
104 ASSERT (data <= coding - 1);
105
106 shift = 0;
107 while (1)
108 {
109 c = first_set (coding);
110 implicit_end = c == coding;
111 explicit_end = ((data & (c - 1)) == data);
112 if (explicit_end | implicit_end)
113 {
Dave Barachc3799992016-08-15 11:12:27 -0400114 uword t = explicit_end & ~implicit_end;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700115 result = ((data << t) | t) << shift;
116 *n_result_bits =
117 /* data bits */ (c == 0 ? BITS (uword) : min_log2 (c))
Dave Barachc3799992016-08-15 11:12:27 -0400118 /* shift bits */ + shift + t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700119 return result;
120 }
121 data -= c;
122 coding ^= c;
123 shift++;
124 }
125
126 /* Never reached. */
127 ASSERT (0);
128 return ~0;
129}
130
131always_inline uword
Dave Barachc3799992016-08-15 11:12:27 -0400132get_data (void *data, uword data_bytes, uword is_signed)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700133{
134 if (data_bytes == 1)
135 return is_signed ? zvec_signed_to_unsigned (*(i8 *) data) : *(u8 *) data;
136 else if (data_bytes == 2)
Dave Barachc3799992016-08-15 11:12:27 -0400137 return is_signed ? zvec_signed_to_unsigned (*(i16 *) data) : *(u16 *)
138 data;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700139 else if (data_bytes == 4)
Dave Barachc3799992016-08-15 11:12:27 -0400140 return is_signed ? zvec_signed_to_unsigned (*(i32 *) data) : *(u32 *)
141 data;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700142 else if (data_bytes == 8)
Dave Barachc3799992016-08-15 11:12:27 -0400143 return is_signed ? zvec_signed_to_unsigned (*(i64 *) data) : *(u64 *)
144 data;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700145 else
146 {
147 os_panic ();
148 return ~0;
149 }
150}
151
152always_inline void
Dave Barachc3799992016-08-15 11:12:27 -0400153put_data (void *data, uword data_bytes, uword is_signed, uword x)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700154{
155 if (data_bytes == 1)
156 {
157 if (is_signed)
158 *(i8 *) data = zvec_unsigned_to_signed (x);
159 else
160 *(u8 *) data = x;
161 }
162 else if (data_bytes == 2)
163 {
164 if (is_signed)
165 *(i16 *) data = zvec_unsigned_to_signed (x);
166 else
167 *(u16 *) data = x;
168 }
169 else if (data_bytes == 4)
170 {
171 if (is_signed)
172 *(i32 *) data = zvec_unsigned_to_signed (x);
173 else
174 *(u32 *) data = x;
175 }
176 else if (data_bytes == 8)
177 {
178 if (is_signed)
179 *(i64 *) data = zvec_unsigned_to_signed (x);
180 else
181 *(u64 *) data = x;
182 }
183 else
184 {
185 os_panic ();
186 }
187}
188
189always_inline uword *
190zvec_encode_inline (uword * zvec,
191 uword * zvec_n_bits,
192 uword coding,
Dave Barachc3799992016-08-15 11:12:27 -0400193 void *data,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700194 uword data_stride,
Dave Barachc3799992016-08-15 11:12:27 -0400195 uword n_data, uword data_bytes, uword is_signed)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700196{
197 uword i;
198
199 i = *zvec_n_bits;
200 while (n_data >= 1)
201 {
202 uword d0, z0, l0;
203
Dave Barachc3799992016-08-15 11:12:27 -0400204 d0 = get_data (data + 0 * data_stride, data_bytes, is_signed);
205 data += 1 * data_stride;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700206 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
Dave Barachc3799992016-08-15 11:12:27 -0400232_(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);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700240
241#undef _
242
243always_inline uword
244coding_max_n_bits (uword coding)
245{
246 uword n_bits;
247 (void) zvec_decode (coding, 0, &n_bits);
248 return n_bits;
249}
250
251always_inline void
252zvec_decode_inline (uword * zvec,
253 uword * zvec_n_bits,
254 uword coding,
Dave Barachc3799992016-08-15 11:12:27 -0400255 void *data,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700256 uword data_stride,
Dave Barachc3799992016-08-15 11:12:27 -0400257 uword n_data, uword data_bytes, uword is_signed)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700258{
259 uword i, n_max;
260
261 i = *zvec_n_bits;
262 n_max = coding_max_n_bits (coding);
263 while (n_data >= 1)
264 {
265 uword d0, z0, l0;
266
267 z0 = clib_bitmap_get_multiple (zvec, i, n_max);
268 d0 = zvec_decode (coding, z0, &l0);
269 i += l0;
Dave Barachc3799992016-08-15 11:12:27 -0400270 put_data (data + 0 * data_stride, data_bytes, is_signed, d0);
271 data += 1 * data_stride;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700272 n_data -= 1;
273 }
274 *zvec_n_bits = i;
275}
276
277#define _(TYPE,IS_SIGNED) \
278 void zvec_decode_##TYPE (uword * zvec, \
279 uword * zvec_n_bits, \
280 uword coding, \
281 void * data, \
282 uword data_stride, \
283 uword n_data) \
284 { \
285 return zvec_decode_inline (zvec, zvec_n_bits, \
286 coding, \
287 data, data_stride, n_data, \
288 /* data_bytes */ sizeof (TYPE), \
289 /* is_signed */ IS_SIGNED); \
290 }
291
Dave Barachc3799992016-08-15 11:12:27 -0400292_(u8, /* is_signed */ 0);
293_(u16, /* is_signed */ 0);
294_(u32, /* is_signed */ 0);
295_(u64, /* is_signed */ 0);
296_(i8, /* is_signed */ 1);
297_(i16, /* is_signed */ 1);
298_(i32, /* is_signed */ 1);
299_(i64, /* is_signed */ 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700300
301#undef _
302
303/* Compute number of bits needed to encode given histogram. */
Dave Barachc3799992016-08-15 11:12:27 -0400304static uword
305zvec_coding_bits (uword coding, uword * histogram_counts, uword min_bits)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700306{
307 uword n_type_bits, n_bits;
308 uword this_count, last_count, max_count_index;
309 uword i, b, l;
310
311 n_bits = 0;
312 n_type_bits = 1;
313 last_count = 0;
314 max_count_index = vec_len (histogram_counts) - 1;
315
316 /* Coding is not large enough to encode given data. */
317 if (coding <= max_count_index)
318 return ~0;
319
320 i = 0;
321 while (coding != 0)
322 {
323 b = first_set (coding);
324 l = min_log2 (b);
325 i += b;
326
Dave Barachc3799992016-08-15 11:12:27 -0400327 this_count =
328 histogram_counts[i > max_count_index ? max_count_index : i - 1];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700329
330 /* No more data to encode? */
331 if (this_count == last_count)
332 break;
333
334 /* Last coding is i 0 ... 0 so we don't need an extra type bit. */
335 if (coding == b)
336 n_type_bits--;
337
338 n_bits += (this_count - last_count) * (n_type_bits + l);
339
340 /* This coding cannot be minimal: so return. */
341 if (n_bits >= min_bits)
342 return ~0;
343
344 last_count = this_count;
345 coding ^= b;
346 n_type_bits++;
347 }
348
349 return n_bits;
350}
351
352uword
Dave Barachc3799992016-08-15 11:12:27 -0400353_zvec_coding_from_histogram (void *histogram,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700354 uword histogram_len,
355 uword histogram_elt_count_offset,
356 uword histogram_elt_bytes,
357 uword max_value_to_encode,
358 zvec_coding_info_t * coding_return)
359{
360 uword coding, min_coding;
361 uword min_coding_bits, coding_bits;
362 uword i, n_bits_set, total_count;
Dave Barachc3799992016-08-15 11:12:27 -0400363 uword *counts;
364 zvec_histogram_count_t *h_count = histogram + histogram_elt_count_offset;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700365
366 if (histogram_len < 1)
367 {
368 coding_return->coding = 0;
369 coding_return->min_coding_bits = 0;
370 coding_return->n_data = 0;
371 coding_return->n_codes = 0;
372 coding_return->ave_coding_bits = 0;
373 return 0;
374 }
375
376 total_count = 0;
377 counts = vec_new (uword, histogram_len);
378 for (i = 0; i < histogram_len; i++)
379 {
380 zvec_histogram_count_t this_count = h_count[0];
381 total_count += this_count;
382 counts[i] = total_count;
Dave Barachc3799992016-08-15 11:12:27 -0400383 h_count =
384 (zvec_histogram_count_t *) ((void *) h_count + histogram_elt_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700385 }
386
387 min_coding = 0;
388 min_coding_bits = ~0;
389
390 {
Dave Barachc3799992016-08-15 11:12:27 -0400391 uword base_coding =
392 max_value_to_encode !=
393 ~0 ? (1 + max_value_to_encode) : vec_len (counts);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700394 uword max_coding = max_pow2 (2 * base_coding);
395
396 for (n_bits_set = 1; n_bits_set <= 8; n_bits_set++)
397 {
398 for (coding = pow2_mask (n_bits_set);
399 coding < max_coding;
400 coding = next_with_same_number_of_set_bits (coding))
401 {
402 coding_bits = zvec_coding_bits (coding, counts, min_coding_bits);
403 if (coding_bits >= min_coding_bits)
404 continue;
405 min_coding_bits = coding_bits;
406 min_coding = coding;
407 }
408 }
409 }
410
411 if (coding_return)
412 {
413 coding_return->coding = min_coding;
414 coding_return->min_coding_bits = min_coding_bits;
415 coding_return->n_data = total_count;
416 coding_return->n_codes = vec_len (counts);
Dave Barachc3799992016-08-15 11:12:27 -0400417 coding_return->ave_coding_bits =
418 (f64) min_coding_bits / (f64) total_count;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700419 }
420
421 vec_free (counts);
422
423 return min_coding;
424}
425
Dave Barachc3799992016-08-15 11:12:27 -0400426u8 *
427format_zvec_coding (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700428{
Dave Barachc3799992016-08-15 11:12:27 -0400429 zvec_coding_info_t *c = va_arg (*args, zvec_coding_info_t *);
430 return format (s,
431 "zvec coding 0x%x, %d elts, %d codes, %d bits total, %.4f ave bits/code",
432 c->coding, c->n_data, c->n_codes, c->min_coding_bits,
433 c->ave_coding_bits);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700434}
Dave Barachc3799992016-08-15 11:12:27 -0400435
436/*
437 * fd.io coding-style-patch-verification: ON
438 *
439 * Local Variables:
440 * eval: (c-set-style "gnu")
441 * End:
442 */