diff --git a/src/utils/utils_generator.c b/src/utils/utils_generator.c new file mode 100644 index 0000000..32b42a2 --- /dev/null +++ b/src/utils/utils_generator.c @@ -0,0 +1,187 @@ +#include "utils_generator.h" + +/** + * @brief Reverse bits of 32-bit value + * + * @param[in] x Value to be reversed + * + * @return Reversed value + */ +static inline uint32_t bitreverse32(register uint32_t x) +{ + x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1)); + x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2)); + x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4)); + x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8)); + return((x >> 16) | (x << 16)); +} + +/** + * @brief Initialize bisect generator state + * + * @param[in] generator Pointer to generator structure + * @param[in] limit Limit of the value returned by generator (maximum value + * returned by the generator is limit - 1) + * @param[in] offset Offset at which generator should start + * + * @return Reversed value + */ +void ocf_generator_bisect_init( + struct ocf_generator_bisect_state *generator, + uint32_t limit, uint32_t offset) +{ + unsigned clz; + uint32_t maplen; + + clz = __builtin_clz(limit - 1); + maplen = 1 << (32 - clz); + + generator->curr = (uint64_t)offset * maplen / limit; + generator->limit = limit; +} + +/** + * @brief Generate next value of bisect generator + * + * This function calculates next value of the generator. The generator + * pattern is based on order of indexes in array visited with bisection + * algorithm, where always the left child is visited first at every depth. + * This can be imagined as a special implementation of BFS done on a full + * binary tree, where visiting nodes on each depth level is done the same + * order as original array (so the algorithm is recursive at each level). + * + * Example: + * + * 1. We generate array of all values for number of bits needed to express + * limit value - 1. + * + * For limit==14 (4 bits) it would be: + * [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] + * + * 2. We take first element of the array, and then build full binary tree + * from other elements (it should always be possible to build a full + * binary tree, as number of remaining elements is always 2^n-1). + * + * The full binary tree for example array looks like this: + * + * Depth 0 -> 8 + * / \ + * / \ + * / \ + * / \ + * / \ + * / \ + * / \ + * / \ + * Depth 1 -> 4 12 + * / \ / \ + * / \ / \ + * / \ / \ + * Depth 2 -> 2 6 10 14 + * / \ / \ / \ / \ + * Depth 3 -> 1 3 5 7 9 11 13 15 + * + * 3. We traverse the tree: + * a) If depth level has one element, we take it. + * b) If depth level has two elements, we take left and then right. + * c) If depth level has more than two elements, we repeat steps + * from 2 on array built from elements on that level left to right. + * + * At level 0 we take 8, at level 1 we take 4 and 12, and at level 3 we + * take 2 and build tree like this one: + * + * 10 + * / \ + * 6 14 + * + * Then at level 0 of that tree we take 10, at level 1 we take 6 and 14, + * and then we go back the original tree. + * + * At level 3 we take 1 and we build another tree from remaining elements + * of that level: + * + * 9 + * / \ + * / \ + * / \ + * 5 13 + * / \ / \ + * 3 7 11 15 + * + * Repeating step 3 on that tree we get elements 9, then 5 and 13, and then + * by running steps from 2 on the lowest level of that tree we get elements + * in following order: 3, 11, 7 and 15. + * + * So the entire sequence would be as follows: + * [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15] + * + * This algorithm is however quite complex, and it can be simplified + * significantly thanks to properties of the result sequence. Note that + * when this sequence is written in binary it looks like this: + * + * 0 0000 + * 8 1000 + * 4 0100 + * 12 1100 + * 2 0010 + * 10 1010 + * 6 0110 + * 14 1110 + * 1 0001 + * 9 1001 + * 5 0101 + * 13 1101 + * 3 0011 + * 11 1011 + * 7 0111 + * 15 1111 + * + * So in its binary representation it looks like a mirror image of binary + * representation of the original sequence: + * + * 0 0000 0000 0 + * 8 1000 0001 1 + * 4 0100 0010 2 + * 12 1100 0011 3 + * 2 0010 0100 4 + * 10 1010 0101 5 + * 6 0110 0110 6 + * 14 1110 0111 7 + * 1 0001 1000 8 + * 9 1001 1001 9 + * 5 0101 1010 10 + * 13 1101 1011 11 + * 3 0011 1100 12 + * 11 1011 1101 13 + * 7 0111 1110 14 + * 15 1111 1111 15 + * + * With that knowledge we can easily calculate the next result value by just + * reversing order of bits for each value in original sequence. + * + * As a result we are left with sequence that contains all the numbers that + * can be expressed with number of bits reqiured to express limit - 1. The only + * thing we need to do at that point is to just filter out values that do not + * fit within the limit. + * + * @param[in] generator Pointer to generator structure + * + * @return Generated value + */ +uint32_t ocf_generator_bisect_next( + struct ocf_generator_bisect_state *generator) +{ + unsigned clz; + uint32_t maplen; + uint32_t value; + + clz = __builtin_clz(generator->limit - 1); + maplen = 1 << (32 - clz); + + do { + value = bitreverse32(generator->curr) >> clz; + generator->curr = (generator->curr + 1) % maplen; + } while (value >= generator->limit); + + return value; +} diff --git a/src/utils/utils_generator.h b/src/utils/utils_generator.h new file mode 100644 index 0000000..068602d --- /dev/null +++ b/src/utils/utils_generator.h @@ -0,0 +1,23 @@ +/* + * Copyright(c) 2022 Intel Corporation + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __UTILS_GENERATOR_H__ +#define __UTILS_GENERATOR_H__ + +#include "ocf/ocf.h" + +struct ocf_generator_bisect_state { + uint32_t curr; + uint32_t limit; +}; + +void ocf_generator_bisect_init( + struct ocf_generator_bisect_state *generator, + uint32_t limit, uint32_t offset); + +uint32_t ocf_generator_bisect_next( + struct ocf_generator_bisect_state *generator); + +#endif /* __UTILS_GENERATOR_H__ */