gorilla.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "gorilla.h"
  3. #include <cassert>
  4. #include <climits>
  5. #include <cstdio>
  6. #include <cstring>
  7. using std::size_t;
  8. template <typename T>
  9. static constexpr size_t bit_size() noexcept
  10. {
  11. static_assert((sizeof(T) * CHAR_BIT) == 32 || (sizeof(T) * CHAR_BIT) == 64,
  12. "Word size should be 32 or 64 bits.");
  13. return (sizeof(T) * CHAR_BIT);
  14. }
  15. static void bit_buffer_write(uint32_t *buf, size_t pos, uint32_t v, size_t nbits)
  16. {
  17. assert(nbits > 0 && nbits <= bit_size<uint32_t>());
  18. const size_t index = pos / bit_size<uint32_t>();
  19. const size_t offset = pos % bit_size<uint32_t>();
  20. pos += nbits;
  21. if (offset == 0) {
  22. buf[index] = v;
  23. } else {
  24. const size_t remaining_bits = bit_size<uint32_t>() - offset;
  25. // write the lower part of the value
  26. const uint32_t low_bits_mask = ((uint32_t) 1 << remaining_bits) - 1;
  27. const uint32_t lowest_bits_in_value = v & low_bits_mask;
  28. buf[index] |= (lowest_bits_in_value << offset);
  29. if (nbits > remaining_bits) {
  30. // write the upper part of the value
  31. const uint32_t high_bits_mask = ~low_bits_mask;
  32. const uint32_t highest_bits_in_value = (v & high_bits_mask) >> (remaining_bits);
  33. buf[index + 1] = highest_bits_in_value;
  34. }
  35. }
  36. }
  37. static void bit_buffer_read(const uint32_t *buf, size_t pos, uint32_t *v, size_t nbits)
  38. {
  39. assert(nbits > 0 && nbits <= bit_size<uint32_t>());
  40. const size_t index = pos / bit_size<uint32_t>();
  41. const size_t offset = pos % bit_size<uint32_t>();
  42. pos += nbits;
  43. if (offset == 0) {
  44. *v = (nbits == bit_size<uint32_t>()) ?
  45. buf[index] :
  46. buf[index] & (((uint32_t) 1 << nbits) - 1);
  47. } else {
  48. const size_t remaining_bits = bit_size<uint32_t>() - offset;
  49. // extract the lower part of the value
  50. if (nbits < remaining_bits) {
  51. *v = (buf[index] >> offset) & (((uint32_t) 1 << nbits) - 1);
  52. } else {
  53. *v = (buf[index] >> offset) & (((uint32_t) 1 << remaining_bits) - 1);
  54. nbits -= remaining_bits;
  55. *v |= (buf[index + 1] & (((uint32_t) 1 << nbits) - 1)) << remaining_bits;
  56. }
  57. }
  58. }
  59. gorilla_writer_t gorilla_writer_init(gorilla_buffer_t *gbuf, size_t n)
  60. {
  61. gorilla_writer_t gw = gorilla_writer_t {
  62. .head_buffer = gbuf,
  63. .last_buffer = NULL,
  64. .prev_number = 0,
  65. .prev_xor_lzc = 0,
  66. .capacity = 0
  67. };
  68. gorilla_writer_add_buffer(&gw, gbuf, n);
  69. return gw;
  70. }
  71. void gorilla_writer_add_buffer(gorilla_writer_t *gw, gorilla_buffer_t *gbuf, size_t n)
  72. {
  73. gbuf->header.next = NULL;
  74. gbuf->header.entries = 0;
  75. gbuf->header.nbits = 0;
  76. uint32_t capacity = (n * bit_size<uint32_t>()) - (sizeof(gorilla_header_t) * CHAR_BIT);
  77. gw->prev_number = 0;
  78. gw->prev_xor_lzc = 0;
  79. gw->capacity = capacity;
  80. if (gw->last_buffer)
  81. gw->last_buffer->header.next = gbuf;
  82. __atomic_store_n(&gw->last_buffer, gbuf, __ATOMIC_RELAXED);
  83. }
  84. uint32_t gorilla_writer_entries(const gorilla_writer_t *gw) {
  85. uint32_t entries = 0;
  86. const gorilla_buffer_t *curr_gbuf = __atomic_load_n(&gw->head_buffer, __ATOMIC_SEQ_CST);
  87. do {
  88. const gorilla_buffer_t *next_gbuf = __atomic_load_n(&curr_gbuf->header.next, __ATOMIC_SEQ_CST);
  89. entries += __atomic_load_n(&curr_gbuf->header.entries, __ATOMIC_SEQ_CST);
  90. curr_gbuf = next_gbuf;
  91. } while (curr_gbuf);
  92. return entries;
  93. }
  94. bool gorilla_writer_write(gorilla_writer_t *gw, uint32_t number)
  95. {
  96. gorilla_header_t *hdr = &gw->last_buffer->header;
  97. uint32_t *data = gw->last_buffer->data;
  98. // this is the first number we are writing
  99. if (hdr->entries == 0) {
  100. if (hdr->nbits + bit_size<uint32_t>() >= gw->capacity)
  101. return false;
  102. bit_buffer_write(data, hdr->nbits, number, bit_size<uint32_t>());
  103. __atomic_fetch_add(&hdr->nbits, bit_size<uint32_t>(), __ATOMIC_RELAXED);
  104. __atomic_fetch_add(&hdr->entries, 1, __ATOMIC_RELAXED);
  105. gw->prev_number = number;
  106. return true;
  107. }
  108. // write true/false based on whether we got the same number or not.
  109. if (number == gw->prev_number) {
  110. if (hdr->nbits + 1 >= gw->capacity)
  111. return false;
  112. bit_buffer_write(data, hdr->nbits, static_cast<uint32_t>(1), 1);
  113. __atomic_fetch_add(&hdr->nbits, 1, __ATOMIC_RELAXED);
  114. __atomic_fetch_add(&hdr->entries, 1, __ATOMIC_RELAXED);
  115. return true;
  116. }
  117. if (hdr->nbits + 1 >= gw->capacity)
  118. return false;
  119. bit_buffer_write(data, hdr->nbits, static_cast<uint32_t>(0), 1);
  120. __atomic_fetch_add(&hdr->nbits, 1, __ATOMIC_RELAXED);
  121. uint32_t xor_value = gw->prev_number ^ number;
  122. uint32_t xor_lzc = (bit_size<uint32_t>() == 32) ? __builtin_clz(xor_value) : __builtin_clzll(xor_value);
  123. uint32_t is_xor_lzc_same = (xor_lzc == gw->prev_xor_lzc) ? 1 : 0;
  124. if (hdr->nbits + 1 >= gw->capacity)
  125. return false;
  126. bit_buffer_write(data, hdr->nbits, is_xor_lzc_same, 1);
  127. __atomic_fetch_add(&hdr->nbits, 1, __ATOMIC_RELAXED);
  128. if (!is_xor_lzc_same) {
  129. if (hdr->nbits + 1 >= gw->capacity)
  130. return false;
  131. bit_buffer_write(data, hdr->nbits, xor_lzc, (bit_size<uint32_t>() == 32) ? 5 : 6);
  132. __atomic_fetch_add(&hdr->nbits, (bit_size<uint32_t>() == 32) ? 5 : 6, __ATOMIC_RELAXED);
  133. }
  134. // write the bits of the XOR'd value without the LZC prefix
  135. if (hdr->nbits + (bit_size<uint32_t>() - xor_lzc) >= gw->capacity)
  136. return false;
  137. bit_buffer_write(data, hdr->nbits, xor_value, bit_size<uint32_t>() - xor_lzc);
  138. __atomic_fetch_add(&hdr->nbits, bit_size<uint32_t>() - xor_lzc, __ATOMIC_RELAXED);
  139. __atomic_fetch_add(&hdr->entries, 1, __ATOMIC_RELAXED);
  140. gw->prev_number = number;
  141. gw->prev_xor_lzc = xor_lzc;
  142. return true;
  143. }
  144. gorilla_buffer_t *gorilla_writer_drop_head_buffer(gorilla_writer_t *gw) {
  145. if (!gw->head_buffer)
  146. return NULL;
  147. gorilla_buffer_t *curr_head = gw->head_buffer;
  148. gorilla_buffer_t *next_head = gw->head_buffer->header.next;
  149. __atomic_store_n(&gw->head_buffer, next_head, __ATOMIC_RELAXED);
  150. return curr_head;
  151. }
  152. uint32_t gorilla_writer_nbytes(const gorilla_writer_t *gw)
  153. {
  154. uint32_t nbits = 0;
  155. const gorilla_buffer_t *curr_gbuf = __atomic_load_n(&gw->head_buffer, __ATOMIC_SEQ_CST);
  156. do {
  157. const gorilla_buffer_t *next_gbuf = __atomic_load_n(&curr_gbuf->header.next, __ATOMIC_SEQ_CST);
  158. nbits += __atomic_load_n(&curr_gbuf->header.nbits, __ATOMIC_SEQ_CST);
  159. curr_gbuf = next_gbuf;
  160. } while (curr_gbuf);
  161. return (nbits + (CHAR_BIT - 1)) / CHAR_BIT;
  162. }
  163. bool gorilla_writer_serialize(const gorilla_writer_t *gw, uint8_t *dst, uint32_t dst_size) {
  164. const gorilla_buffer_t *curr_gbuf = gw->head_buffer;
  165. do {
  166. const gorilla_buffer_t *next_gbuf = curr_gbuf->header.next;
  167. size_t bytes = GORILLA_BUFFER_SIZE;
  168. if (bytes > dst_size)
  169. return false;
  170. memcpy(dst, curr_gbuf, bytes);
  171. dst += bytes;
  172. dst_size -= bytes;
  173. curr_gbuf = next_gbuf;
  174. } while (curr_gbuf);
  175. return true;
  176. }
  177. uint32_t gorilla_buffer_patch(gorilla_buffer_t *gbuf) {
  178. gorilla_buffer_t *curr_gbuf = gbuf;
  179. uint32_t n = curr_gbuf->header.entries;
  180. while (curr_gbuf->header.next) {
  181. uint32_t *buf = reinterpret_cast<uint32_t *>(gbuf);
  182. gbuf = reinterpret_cast<gorilla_buffer_t *>(&buf[GORILLA_BUFFER_SLOTS]);
  183. assert(((uintptr_t) (gbuf) % sizeof(uintptr_t)) == 0 &&
  184. "Gorilla buffer not aligned to uintptr_t");
  185. curr_gbuf->header.next = gbuf;
  186. curr_gbuf = curr_gbuf->header.next;
  187. n += curr_gbuf->header.entries;
  188. }
  189. return n;
  190. }
  191. gorilla_reader_t gorilla_writer_get_reader(const gorilla_writer_t *gw)
  192. {
  193. const gorilla_buffer_t *buffer = __atomic_load_n(&gw->head_buffer, __ATOMIC_SEQ_CST);
  194. uint32_t entries = __atomic_load_n(&buffer->header.entries, __ATOMIC_SEQ_CST);
  195. uint32_t capacity = __atomic_load_n(&buffer->header.nbits, __ATOMIC_SEQ_CST);
  196. return gorilla_reader_t {
  197. .buffer = buffer,
  198. .entries = entries,
  199. .index = 0,
  200. .capacity = capacity,
  201. .position = 0,
  202. .prev_number = 0,
  203. .prev_xor_lzc = 0,
  204. .prev_xor = 0,
  205. };
  206. }
  207. gorilla_reader_t gorilla_reader_init(gorilla_buffer_t *gbuf)
  208. {
  209. uint32_t entries = __atomic_load_n(&gbuf->header.entries, __ATOMIC_SEQ_CST);
  210. uint32_t capacity = __atomic_load_n(&gbuf->header.nbits, __ATOMIC_SEQ_CST);
  211. return gorilla_reader_t {
  212. .buffer = gbuf,
  213. .entries = entries,
  214. .index = 0,
  215. .capacity = capacity,
  216. .position = 0,
  217. .prev_number = 0,
  218. .prev_xor_lzc = 0,
  219. .prev_xor = 0,
  220. };
  221. }
  222. bool gorilla_reader_read(gorilla_reader_t *gr, uint32_t *number)
  223. {
  224. const uint32_t *data = gr->buffer->data;
  225. if (gr->index + 1 > gr->entries) {
  226. // We don't have any more entries to return. However, the writer
  227. // might have updated the buffer's entries. We need to check once
  228. // more in case more elements were added.
  229. gr->entries = __atomic_load_n(&gr->buffer->header.entries, __ATOMIC_SEQ_CST);
  230. gr->capacity = __atomic_load_n(&gr->buffer->header.nbits, __ATOMIC_SEQ_CST);
  231. // if the reader's current buffer has not been updated, we need to
  232. // check if it has a pointer to a next buffer.
  233. if (gr->index + 1 > gr->entries) {
  234. gorilla_buffer_t *next_buffer = __atomic_load_n(&gr->buffer->header.next, __ATOMIC_SEQ_CST);
  235. if (!next_buffer) {
  236. // fprintf(stderr, "Consumed reader with %zu entries from buffer %p\n (No more buffers to read from)", gr->length, gr->buffer);
  237. return false;
  238. }
  239. // fprintf(stderr, "Consumed reader with %zu entries from buffer %p\n", gr->length, gr->buffer);
  240. *gr = gorilla_reader_init(next_buffer);
  241. return gorilla_reader_read(gr, number);
  242. }
  243. }
  244. // read the first number
  245. if (gr->index == 0) {
  246. bit_buffer_read(data, gr->position, number, bit_size<uint32_t>());
  247. gr->index++;
  248. gr->position += bit_size<uint32_t>();
  249. gr->prev_number = *number;
  250. return true;
  251. }
  252. // process same-number bit
  253. uint32_t is_same_number;
  254. bit_buffer_read(data, gr->position, &is_same_number, 1);
  255. gr->position++;
  256. if (is_same_number) {
  257. *number = gr->prev_number;
  258. gr->index++;
  259. return true;
  260. }
  261. // proceess same-xor-lzc bit
  262. uint32_t xor_lzc = gr->prev_xor_lzc;
  263. uint32_t same_xor_lzc;
  264. bit_buffer_read(data, gr->position, &same_xor_lzc, 1);
  265. gr->position++;
  266. if (!same_xor_lzc) {
  267. bit_buffer_read(data, gr->position, &xor_lzc, (bit_size<uint32_t>() == 32) ? 5 : 6);
  268. gr->position += (bit_size<uint32_t>() == 32) ? 5 : 6;
  269. }
  270. // process the non-lzc suffix
  271. uint32_t xor_value = 0;
  272. bit_buffer_read(data, gr->position, &xor_value, bit_size<uint32_t>() - xor_lzc);
  273. gr->position += bit_size<uint32_t>() - xor_lzc;
  274. *number = (gr->prev_number ^ xor_value);
  275. gr->index++;
  276. gr->prev_number = *number;
  277. gr->prev_xor_lzc = xor_lzc;
  278. gr->prev_xor = xor_value;
  279. return true;
  280. }
  281. /*
  282. * Internal code used for fuzzing the library
  283. */
  284. #ifdef ENABLE_FUZZER
  285. #include <vector>
  286. template<typename Word>
  287. static std::vector<Word> random_vector(const uint8_t *data, size_t size) {
  288. std::vector<Word> V;
  289. V.reserve(1024);
  290. while (size >= sizeof(Word)) {
  291. size -= sizeof(Word);
  292. Word w;
  293. memcpy(&w, &data[size], sizeof(Word));
  294. V.push_back(w);
  295. }
  296. return V;
  297. }
  298. class Storage {
  299. public:
  300. gorilla_buffer_t *alloc_buffer(size_t words) {
  301. uint32_t *new_buffer = new uint32_t[words]();
  302. assert(((((uintptr_t) new_buffer) % 8u) == 0) && "Unaligned buffer...");
  303. Buffers.push_back(new_buffer);
  304. return reinterpret_cast<gorilla_buffer_t *>(new_buffer);
  305. }
  306. void free_buffers() {
  307. for (uint32_t *buffer : Buffers) {
  308. delete[] buffer;
  309. }
  310. }
  311. private:
  312. std::vector<uint32_t *> Buffers;
  313. };
  314. extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
  315. if (Size < 4)
  316. return 0;
  317. std::vector<uint32_t> RandomData = random_vector<uint32_t>(Data, Size);
  318. Storage S;
  319. size_t words_per_buffer = 8;
  320. /*
  321. * write data
  322. */
  323. gorilla_buffer_t *first_buffer = S.alloc_buffer(words_per_buffer);
  324. gorilla_writer_t gw = gorilla_writer_init(first_buffer, words_per_buffer);
  325. for (size_t i = 0; i != RandomData.size(); i++) {
  326. bool ok = gorilla_writer_write(&gw, RandomData[i]);
  327. if (ok)
  328. continue;
  329. // add new buffer
  330. gorilla_buffer_t *buffer = S.alloc_buffer(words_per_buffer);
  331. gorilla_writer_add_buffer(&gw, buffer, words_per_buffer);
  332. ok = gorilla_writer_write(&gw, RandomData[i]);
  333. assert(ok && "Could not write data to new buffer!!!");
  334. }
  335. /*
  336. * read data
  337. */
  338. gorilla_reader_t gr = gorilla_writer_get_reader(&gw);
  339. for (size_t i = 0; i != RandomData.size(); i++) {
  340. uint32_t number = 0;
  341. bool ok = gorilla_reader_read(&gr, &number);
  342. assert(ok && "Failed to read number from gorilla buffer");
  343. assert((number == RandomData[i])
  344. && "Read wrong number from gorilla buffer");
  345. }
  346. S.free_buffers();
  347. return 0;
  348. }
  349. #endif /* ENABLE_FUZZER */
  350. #ifdef ENABLE_BENCHMARK
  351. #include <benchmark/benchmark.h>
  352. #include <random>
  353. static size_t NumItems = 1024;
  354. static void BM_EncodeU32Numbers(benchmark::State& state) {
  355. std::random_device rd;
  356. std::mt19937 mt(rd());
  357. std::uniform_int_distribution<uint32_t> dist(0x0, 0x0000FFFF);
  358. std::vector<uint32_t> RandomData;
  359. for (size_t idx = 0; idx != NumItems; idx++) {
  360. RandomData.push_back(dist(mt));
  361. }
  362. std::vector<uint32_t> EncodedData(10 * RandomData.capacity(), 0);
  363. for (auto _ : state) {
  364. gorilla_writer_t gw = gorilla_writer_init(
  365. reinterpret_cast<gorilla_buffer_t *>(EncodedData.data()),
  366. EncodedData.size());
  367. for (size_t i = 0; i != RandomData.size(); i++)
  368. benchmark::DoNotOptimize(gorilla_writer_write(&gw, RandomData[i]));
  369. benchmark::ClobberMemory();
  370. }
  371. state.SetItemsProcessed(NumItems * state.iterations());
  372. state.SetBytesProcessed(NumItems * state.iterations() * sizeof(uint32_t));
  373. }
  374. BENCHMARK(BM_EncodeU32Numbers)->ThreadRange(1, 16)->UseRealTime();
  375. static void BM_DecodeU32Numbers(benchmark::State& state) {
  376. std::random_device rd;
  377. std::mt19937 mt(rd());
  378. std::uniform_int_distribution<uint32_t> dist(0x0, 0xFFFFFFFF);
  379. std::vector<uint32_t> RandomData;
  380. for (size_t idx = 0; idx != NumItems; idx++) {
  381. RandomData.push_back(dist(mt));
  382. }
  383. std::vector<uint32_t> EncodedData(10 * RandomData.capacity(), 0);
  384. std::vector<uint32_t> DecodedData(10 * RandomData.capacity(), 0);
  385. gorilla_writer_t gw = gorilla_writer_init(
  386. reinterpret_cast<gorilla_buffer_t *>(EncodedData.data()),
  387. EncodedData.size());
  388. for (size_t i = 0; i != RandomData.size(); i++)
  389. gorilla_writer_write(&gw, RandomData[i]);
  390. for (auto _ : state) {
  391. gorilla_reader_t gr = gorilla_reader_init(reinterpret_cast<gorilla_buffer_t *>(EncodedData.data()));
  392. for (size_t i = 0; i != RandomData.size(); i++) {
  393. uint32_t number = 0;
  394. benchmark::DoNotOptimize(gorilla_reader_read(&gr, &number));
  395. }
  396. benchmark::ClobberMemory();
  397. }
  398. state.SetItemsProcessed(NumItems * state.iterations());
  399. state.SetBytesProcessed(NumItems * state.iterations() * sizeof(uint32_t));
  400. }
  401. BENCHMARK(BM_DecodeU32Numbers)->ThreadRange(1, 16)->UseRealTime();
  402. #endif /* ENABLE_BENCHMARK */