xref: /aosp_15_r20/external/cronet/third_party/brotli/enc/block_splitter_inc.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 /* NOLINT(build/header_guard) */
2 /* Copyright 2013 Google Inc. All Rights Reserved.
3 
4    Distributed under MIT license.
5    See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
6 */
7 
8 /* template parameters: FN, DataType */
9 
10 #define HistogramType FN(Histogram)
11 
FN(InitialEntropyCodes)12 static void FN(InitialEntropyCodes)(const DataType* data, size_t length,
13                                     size_t stride,
14                                     size_t num_histograms,
15                                     HistogramType* histograms) {
16   uint32_t seed = 7;
17   size_t block_length = length / num_histograms;
18   size_t i;
19   FN(ClearHistograms)(histograms, num_histograms);
20   for (i = 0; i < num_histograms; ++i) {
21     size_t pos = length * i / num_histograms;
22     if (i != 0) {
23       pos += MyRand(&seed) % block_length;
24     }
25     if (pos + stride >= length) {
26       pos = length - stride - 1;
27     }
28     FN(HistogramAddVector)(&histograms[i], data + pos, stride);
29   }
30 }
31 
FN(RandomSample)32 static void FN(RandomSample)(uint32_t* seed,
33                              const DataType* data,
34                              size_t length,
35                              size_t stride,
36                              HistogramType* sample) {
37   size_t pos = 0;
38   if (stride >= length) {
39     stride = length;
40   } else {
41     pos = MyRand(seed) % (length - stride + 1);
42   }
43   FN(HistogramAddVector)(sample, data + pos, stride);
44 }
45 
FN(RefineEntropyCodes)46 static void FN(RefineEntropyCodes)(const DataType* data, size_t length,
47                                    size_t stride,
48                                    size_t num_histograms,
49                                    HistogramType* histograms,
50                                    HistogramType* tmp) {
51   size_t iters =
52       kIterMulForRefining * length / stride + kMinItersForRefining;
53   uint32_t seed = 7;
54   size_t iter;
55   iters = ((iters + num_histograms - 1) / num_histograms) * num_histograms;
56   for (iter = 0; iter < iters; ++iter) {
57     FN(HistogramClear)(tmp);
58     FN(RandomSample)(&seed, data, length, stride, tmp);
59     FN(HistogramAddHistogram)(&histograms[iter % num_histograms], tmp);
60   }
61 }
62 
63 /* Assigns a block id from the range [0, num_histograms) to each data element
64    in data[0..length) and fills in block_id[0..length) with the assigned values.
65    Returns the number of blocks, i.e. one plus the number of block switches. */
FN(FindBlocks)66 static size_t FN(FindBlocks)(const DataType* data, const size_t length,
67                              const double block_switch_bitcost,
68                              const size_t num_histograms,
69                              const HistogramType* histograms,
70                              double* insert_cost,
71                              double* cost,
72                              uint8_t* switch_signal,
73                              uint8_t* block_id) {
74   const size_t alphabet_size = FN(HistogramDataSize)();
75   const size_t bitmap_len = (num_histograms + 7) >> 3;
76   size_t num_blocks = 1;
77   size_t byte_ix;
78   size_t i;
79   size_t j;
80   BROTLI_DCHECK(num_histograms <= 256);
81 
82   /* Trivial case: single historgram -> single block type. */
83   if (num_histograms <= 1) {
84     for (i = 0; i < length; ++i) {
85       block_id[i] = 0;
86     }
87     return 1;
88   }
89 
90   /* Fill bitcost for each symbol of all histograms.
91    * Non-existing symbol cost: 2 + log2(total_count).
92    * Regular symbol cost: -log2(symbol_count / total_count). */
93   memset(insert_cost, 0,
94          sizeof(insert_cost[0]) * alphabet_size * num_histograms);
95   for (i = 0; i < num_histograms; ++i) {
96     insert_cost[i] = FastLog2((uint32_t)histograms[i].total_count_);
97   }
98   for (i = alphabet_size; i != 0;) {
99     /* Reverse order to use the 0-th row as a temporary storage. */
100     --i;
101     for (j = 0; j < num_histograms; ++j) {
102       insert_cost[i * num_histograms + j] =
103           insert_cost[j] - BitCost(histograms[j].data_[i]);
104     }
105   }
106 
107   /* After each iteration of this loop, cost[k] will contain the difference
108      between the minimum cost of arriving at the current byte position using
109      entropy code k, and the minimum cost of arriving at the current byte
110      position. This difference is capped at the block switch cost, and if it
111      reaches block switch cost, it means that when we trace back from the last
112      position, we need to switch here. */
113   memset(cost, 0, sizeof(cost[0]) * num_histograms);
114   memset(switch_signal, 0, sizeof(switch_signal[0]) * length * bitmap_len);
115   for (byte_ix = 0; byte_ix < length; ++byte_ix) {
116     size_t ix = byte_ix * bitmap_len;
117     size_t symbol = data[byte_ix];
118     size_t insert_cost_ix = symbol * num_histograms;
119     double min_cost = 1e99;
120     double block_switch_cost = block_switch_bitcost;
121     size_t k;
122     for (k = 0; k < num_histograms; ++k) {
123       /* We are coding the symbol with entropy code k. */
124       cost[k] += insert_cost[insert_cost_ix + k];
125       if (cost[k] < min_cost) {
126         min_cost = cost[k];
127         block_id[byte_ix] = (uint8_t)k;
128       }
129     }
130     /* More blocks for the beginning. */
131     if (byte_ix < 2000) {
132       block_switch_cost *= 0.77 + 0.07 * (double)byte_ix / 2000;
133     }
134     for (k = 0; k < num_histograms; ++k) {
135       cost[k] -= min_cost;
136       if (cost[k] >= block_switch_cost) {
137         const uint8_t mask = (uint8_t)(1u << (k & 7));
138         cost[k] = block_switch_cost;
139         BROTLI_DCHECK((k >> 3) < bitmap_len);
140         switch_signal[ix + (k >> 3)] |= mask;
141       }
142     }
143   }
144 
145   byte_ix = length - 1;
146   {  /* Trace back from the last position and switch at the marked places. */
147     size_t ix = byte_ix * bitmap_len;
148     uint8_t cur_id = block_id[byte_ix];
149     while (byte_ix > 0) {
150       const uint8_t mask = (uint8_t)(1u << (cur_id & 7));
151       BROTLI_DCHECK(((size_t)cur_id >> 3) < bitmap_len);
152       --byte_ix;
153       ix -= bitmap_len;
154       if (switch_signal[ix + (cur_id >> 3)] & mask) {
155         if (cur_id != block_id[byte_ix]) {
156           cur_id = block_id[byte_ix];
157           ++num_blocks;
158         }
159       }
160       block_id[byte_ix] = cur_id;
161     }
162   }
163   return num_blocks;
164 }
165 
FN(RemapBlockIds)166 static size_t FN(RemapBlockIds)(uint8_t* block_ids, const size_t length,
167                                 uint16_t* new_id, const size_t num_histograms) {
168   static const uint16_t kInvalidId = 256;
169   uint16_t next_id = 0;
170   size_t i;
171   for (i = 0; i < num_histograms; ++i) {
172     new_id[i] = kInvalidId;
173   }
174   for (i = 0; i < length; ++i) {
175     BROTLI_DCHECK(block_ids[i] < num_histograms);
176     if (new_id[block_ids[i]] == kInvalidId) {
177       new_id[block_ids[i]] = next_id++;
178     }
179   }
180   for (i = 0; i < length; ++i) {
181     block_ids[i] = (uint8_t)new_id[block_ids[i]];
182     BROTLI_DCHECK(block_ids[i] < num_histograms);
183   }
184   BROTLI_DCHECK(next_id <= num_histograms);
185   return next_id;
186 }
187 
FN(BuildBlockHistograms)188 static void FN(BuildBlockHistograms)(const DataType* data, const size_t length,
189                                      const uint8_t* block_ids,
190                                      const size_t num_histograms,
191                                      HistogramType* histograms) {
192   size_t i;
193   FN(ClearHistograms)(histograms, num_histograms);
194   for (i = 0; i < length; ++i) {
195     FN(HistogramAdd)(&histograms[block_ids[i]], data[i]);
196   }
197 }
198 
199 /* Given the initial partitioning build partitioning with limited number
200  * of histograms (and block types). */
FN(ClusterBlocks)201 static void FN(ClusterBlocks)(MemoryManager* m,
202                               const DataType* data, const size_t length,
203                               const size_t num_blocks,
204                               uint8_t* block_ids,
205                               BlockSplit* split) {
206   uint32_t* histogram_symbols = BROTLI_ALLOC(m, uint32_t, num_blocks);
207   uint32_t* u32 =
208       BROTLI_ALLOC(m, uint32_t, num_blocks + 4 * HISTOGRAMS_PER_BATCH);
209   const size_t expected_num_clusters = CLUSTERS_PER_BATCH *
210       (num_blocks + HISTOGRAMS_PER_BATCH - 1) / HISTOGRAMS_PER_BATCH;
211   size_t all_histograms_size = 0;
212   size_t all_histograms_capacity = expected_num_clusters;
213   HistogramType* all_histograms =
214       BROTLI_ALLOC(m, HistogramType, all_histograms_capacity);
215   size_t cluster_size_size = 0;
216   size_t cluster_size_capacity = expected_num_clusters;
217   uint32_t* cluster_size = BROTLI_ALLOC(m, uint32_t, cluster_size_capacity);
218   size_t num_clusters = 0;
219   HistogramType* histograms = BROTLI_ALLOC(m, HistogramType,
220       BROTLI_MIN(size_t, num_blocks, HISTOGRAMS_PER_BATCH));
221   size_t max_num_pairs =
222       HISTOGRAMS_PER_BATCH * HISTOGRAMS_PER_BATCH / 2;
223   size_t pairs_capacity = max_num_pairs + 1;
224   HistogramPair* pairs = BROTLI_ALLOC(m, HistogramPair, pairs_capacity);
225   size_t pos = 0;
226   uint32_t* clusters;
227   size_t num_final_clusters;
228   static const uint32_t kInvalidIndex = BROTLI_UINT32_MAX;
229   uint32_t* new_index;
230   size_t i;
231   uint32_t* BROTLI_RESTRICT const sizes = u32 + 0 * HISTOGRAMS_PER_BATCH;
232   uint32_t* BROTLI_RESTRICT const new_clusters = u32 + 1 * HISTOGRAMS_PER_BATCH;
233   uint32_t* BROTLI_RESTRICT const symbols = u32 + 2 * HISTOGRAMS_PER_BATCH;
234   uint32_t* BROTLI_RESTRICT const remap = u32 + 3 * HISTOGRAMS_PER_BATCH;
235   uint32_t* BROTLI_RESTRICT const block_lengths =
236       u32 + 4 * HISTOGRAMS_PER_BATCH;
237   /* TODO(eustas): move to arena? */
238   HistogramType* tmp = BROTLI_ALLOC(m, HistogramType, 2);
239 
240   if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(histogram_symbols) ||
241       BROTLI_IS_NULL(u32) || BROTLI_IS_NULL(all_histograms) ||
242       BROTLI_IS_NULL(cluster_size) || BROTLI_IS_NULL(histograms) ||
243       BROTLI_IS_NULL(pairs) || BROTLI_IS_NULL(tmp)) {
244     return;
245   }
246 
247   memset(u32, 0, (num_blocks + 4 * HISTOGRAMS_PER_BATCH) * sizeof(uint32_t));
248 
249   /* Calculate block lengths (convert repeating values -> series length). */
250   {
251     size_t block_idx = 0;
252     for (i = 0; i < length; ++i) {
253       BROTLI_DCHECK(block_idx < num_blocks);
254       ++block_lengths[block_idx];
255       if (i + 1 == length || block_ids[i] != block_ids[i + 1]) {
256         ++block_idx;
257       }
258     }
259     BROTLI_DCHECK(block_idx == num_blocks);
260   }
261 
262   /* Pre-cluster blocks (cluster batches). */
263   for (i = 0; i < num_blocks; i += HISTOGRAMS_PER_BATCH) {
264     const size_t num_to_combine =
265         BROTLI_MIN(size_t, num_blocks - i, HISTOGRAMS_PER_BATCH);
266     size_t num_new_clusters;
267     size_t j;
268     for (j = 0; j < num_to_combine; ++j) {
269       size_t k;
270       size_t block_length = block_lengths[i + j];
271       FN(HistogramClear)(&histograms[j]);
272       for (k = 0; k < block_length; ++k) {
273         FN(HistogramAdd)(&histograms[j], data[pos++]);
274       }
275       histograms[j].bit_cost_ = FN(BrotliPopulationCost)(&histograms[j]);
276       new_clusters[j] = (uint32_t)j;
277       symbols[j] = (uint32_t)j;
278       sizes[j] = 1;
279     }
280     num_new_clusters = FN(BrotliHistogramCombine)(
281         histograms, tmp, sizes, symbols, new_clusters, pairs, num_to_combine,
282         num_to_combine, HISTOGRAMS_PER_BATCH, max_num_pairs);
283     BROTLI_ENSURE_CAPACITY(m, HistogramType, all_histograms,
284         all_histograms_capacity, all_histograms_size + num_new_clusters);
285     BROTLI_ENSURE_CAPACITY(m, uint32_t, cluster_size,
286         cluster_size_capacity, cluster_size_size + num_new_clusters);
287     if (BROTLI_IS_OOM(m)) return;
288     for (j = 0; j < num_new_clusters; ++j) {
289       all_histograms[all_histograms_size++] = histograms[new_clusters[j]];
290       cluster_size[cluster_size_size++] = sizes[new_clusters[j]];
291       remap[new_clusters[j]] = (uint32_t)j;
292     }
293     for (j = 0; j < num_to_combine; ++j) {
294       histogram_symbols[i + j] = (uint32_t)num_clusters + remap[symbols[j]];
295     }
296     num_clusters += num_new_clusters;
297     BROTLI_DCHECK(num_clusters == cluster_size_size);
298     BROTLI_DCHECK(num_clusters == all_histograms_size);
299   }
300   BROTLI_FREE(m, histograms);
301 
302   /* Final clustering. */
303   max_num_pairs =
304       BROTLI_MIN(size_t, 64 * num_clusters, (num_clusters / 2) * num_clusters);
305   if (pairs_capacity < max_num_pairs + 1) {
306     BROTLI_FREE(m, pairs);
307     pairs = BROTLI_ALLOC(m, HistogramPair, max_num_pairs + 1);
308     if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(pairs)) return;
309   }
310   clusters = BROTLI_ALLOC(m, uint32_t, num_clusters);
311   if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(clusters)) return;
312   for (i = 0; i < num_clusters; ++i) {
313     clusters[i] = (uint32_t)i;
314   }
315   num_final_clusters = FN(BrotliHistogramCombine)(
316       all_histograms, tmp, cluster_size, histogram_symbols, clusters, pairs,
317       num_clusters, num_blocks, BROTLI_MAX_NUMBER_OF_BLOCK_TYPES,
318       max_num_pairs);
319   BROTLI_FREE(m, pairs);
320   BROTLI_FREE(m, cluster_size);
321 
322   /* Assign blocks to final histograms. */
323   new_index = BROTLI_ALLOC(m, uint32_t, num_clusters);
324   if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_index)) return;
325   for (i = 0; i < num_clusters; ++i) new_index[i] = kInvalidIndex;
326   pos = 0;
327   {
328     uint32_t next_index = 0;
329     for (i = 0; i < num_blocks; ++i) {
330       size_t j;
331       uint32_t best_out;
332       double best_bits;
333       FN(HistogramClear)(tmp);
334       for (j = 0; j < block_lengths[i]; ++j) {
335         FN(HistogramAdd)(tmp, data[pos++]);
336       }
337       /* Among equally good histograms prefer last used. */
338       /* TODO(eustas): should we give a block-switch discount here? */
339       best_out = (i == 0) ? histogram_symbols[0] : histogram_symbols[i - 1];
340       best_bits = FN(BrotliHistogramBitCostDistance)(
341           tmp, &all_histograms[best_out], tmp + 1);
342       for (j = 0; j < num_final_clusters; ++j) {
343         const double cur_bits = FN(BrotliHistogramBitCostDistance)(
344             tmp, &all_histograms[clusters[j]], tmp + 1);
345         if (cur_bits < best_bits) {
346           best_bits = cur_bits;
347           best_out = clusters[j];
348         }
349       }
350       histogram_symbols[i] = best_out;
351       if (new_index[best_out] == kInvalidIndex) {
352         new_index[best_out] = next_index++;
353       }
354     }
355   }
356   BROTLI_FREE(m, tmp);
357   BROTLI_FREE(m, clusters);
358   BROTLI_FREE(m, all_histograms);
359   BROTLI_ENSURE_CAPACITY(
360       m, uint8_t, split->types, split->types_alloc_size, num_blocks);
361   BROTLI_ENSURE_CAPACITY(
362       m, uint32_t, split->lengths, split->lengths_alloc_size, num_blocks);
363   if (BROTLI_IS_OOM(m)) return;
364 
365   /* Rewrite final assignment to block-split. There might be less blocks
366    * than |num_blocks| due to clustering. */
367   {
368     uint32_t cur_length = 0;
369     size_t block_idx = 0;
370     uint8_t max_type = 0;
371     for (i = 0; i < num_blocks; ++i) {
372       cur_length += block_lengths[i];
373       if (i + 1 == num_blocks ||
374           histogram_symbols[i] != histogram_symbols[i + 1]) {
375         const uint8_t id = (uint8_t)new_index[histogram_symbols[i]];
376         split->types[block_idx] = id;
377         split->lengths[block_idx] = cur_length;
378         max_type = BROTLI_MAX(uint8_t, max_type, id);
379         cur_length = 0;
380         ++block_idx;
381       }
382     }
383     split->num_blocks = block_idx;
384     split->num_types = (size_t)max_type + 1;
385   }
386   BROTLI_FREE(m, new_index);
387   BROTLI_FREE(m, u32);
388   BROTLI_FREE(m, histogram_symbols);
389 }
390 
391 /* Create BlockSplit (partitioning) given the limits, estimates and "effort"
392  * parameters.
393  *
394  * NB: max_histograms is often less than number of histograms allowed by format;
395  *     this is done intentionally, to save some "space" for context-aware
396  *     clustering (here entropy is estimated for context-free symbols). */
FN(SplitByteVector)397 static void FN(SplitByteVector)(MemoryManager* m,
398                                 const DataType* data, const size_t length,
399                                 const size_t symbols_per_histogram,
400                                 const size_t max_histograms,
401                                 const size_t sampling_stride_length,
402                                 const double block_switch_cost,
403                                 const BrotliEncoderParams* params,
404                                 BlockSplit* split) {
405   const size_t data_size = FN(HistogramDataSize)();
406   HistogramType* histograms;
407   HistogramType* tmp;
408   /* Calculate number of histograms; initial estimate is one histogram per
409    * specified amount of symbols; however, this value is capped. */
410   size_t num_histograms = length / symbols_per_histogram + 1;
411   if (num_histograms > max_histograms) {
412     num_histograms = max_histograms;
413   }
414 
415   /* Corner case: no input. */
416   if (length == 0) {
417     split->num_types = 1;
418     return;
419   }
420 
421   if (length < kMinLengthForBlockSplitting) {
422     BROTLI_ENSURE_CAPACITY(m, uint8_t,
423         split->types, split->types_alloc_size, split->num_blocks + 1);
424     BROTLI_ENSURE_CAPACITY(m, uint32_t,
425         split->lengths, split->lengths_alloc_size, split->num_blocks + 1);
426     if (BROTLI_IS_OOM(m)) return;
427     split->num_types = 1;
428     split->types[split->num_blocks] = 0;
429     split->lengths[split->num_blocks] = (uint32_t)length;
430     split->num_blocks++;
431     return;
432   }
433   histograms = BROTLI_ALLOC(m, HistogramType, num_histograms + 1);
434   tmp = histograms + num_histograms;
435   if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(histograms)) return;
436   /* Find good entropy codes. */
437   FN(InitialEntropyCodes)(data, length,
438                           sampling_stride_length,
439                           num_histograms, histograms);
440   FN(RefineEntropyCodes)(data, length,
441                          sampling_stride_length,
442                          num_histograms, histograms, tmp);
443   {
444     /* Find a good path through literals with the good entropy codes. */
445     uint8_t* block_ids = BROTLI_ALLOC(m, uint8_t, length);
446     size_t num_blocks = 0;
447     const size_t bitmaplen = (num_histograms + 7) >> 3;
448     double* insert_cost = BROTLI_ALLOC(m, double, data_size * num_histograms);
449     double* cost = BROTLI_ALLOC(m, double, num_histograms);
450     uint8_t* switch_signal = BROTLI_ALLOC(m, uint8_t, length * bitmaplen);
451     uint16_t* new_id = BROTLI_ALLOC(m, uint16_t, num_histograms);
452     const size_t iters = params->quality < HQ_ZOPFLIFICATION_QUALITY ? 3 : 10;
453     size_t i;
454     if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(block_ids) ||
455         BROTLI_IS_NULL(insert_cost) || BROTLI_IS_NULL(cost) ||
456         BROTLI_IS_NULL(switch_signal) || BROTLI_IS_NULL(new_id)) {
457       return;
458     }
459     for (i = 0; i < iters; ++i) {
460       num_blocks = FN(FindBlocks)(data, length,
461                                   block_switch_cost,
462                                   num_histograms, histograms,
463                                   insert_cost, cost, switch_signal,
464                                   block_ids);
465       num_histograms = FN(RemapBlockIds)(block_ids, length,
466                                          new_id, num_histograms);
467       FN(BuildBlockHistograms)(data, length, block_ids,
468                                num_histograms, histograms);
469     }
470     BROTLI_FREE(m, insert_cost);
471     BROTLI_FREE(m, cost);
472     BROTLI_FREE(m, switch_signal);
473     BROTLI_FREE(m, new_id);
474     BROTLI_FREE(m, histograms);
475     FN(ClusterBlocks)(m, data, length, num_blocks, block_ids, split);
476     if (BROTLI_IS_OOM(m)) return;
477     BROTLI_FREE(m, block_ids);
478   }
479 }
480 
481 #undef HistogramType
482