Parolin 0.7.9 6796
Console (soon DLLs) to do a tar like job
Loading...
Searching...
No Matches
block_splitter_inc.h
Go to the documentation of this file.
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
12static 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
32static 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
46static 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. */
66static 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
166static 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
188static 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). */
201static 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;
220 BROTLI_MIN(size_t, num_blocks, HISTOGRAMS_PER_BATCH));
221 size_t max_num_pairs =
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 =
237 /* TODO(eustas): move to arena? */
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];
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);
360 m, uint8_t, split->types, split->types_alloc_size, num_blocks);
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). */
397static 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
static const void * data
Definition XzCrc64.c:50
#define BROTLI_MAX_NUMBER_OF_BLOCK_TYPES
Definition constants.h:23
#define FN(X)
Definition backward_references.c:51
double FN BrotliPopulationCost(const HistogramType *histogram)
Definition bit_cost_inc.h:12
#define HISTOGRAMS_PER_BATCH
Definition block_splitter.c:86
#define DataType
Definition block_splitter.c:90
#define CLUSTERS_PER_BATCH
Definition block_splitter.c:87
#define HistogramType
Definition block_splitter_inc.h:10
BROTLI_INTERNAL size_t FN BrotliHistogramCombine(HistogramType *out, uint32_t *cluster_size, uint32_t *symbols, uint32_t *clusters, HistogramPair *pairs, size_t num_clusters, size_t symbols_size, size_t max_clusters, size_t max_num_pairs) CODE(
Definition cluster_inc.h:70
BROTLI_INTERNAL double FN BrotliHistogramBitCostDistance(const HistogramType *histogram, const HistogramType *candidate) CODE(
Definition cluster_inc.h:157
#define BROTLI_ALLOC(M, T, N)
Definition memory.h:44
#define BROTLI_FREE(M, P)
Definition memory.h:48
#define BROTLI_ENSURE_CAPACITY(M, T, A, C, R)
Definition memory.h:81
#define BROTLI_IS_OOM(M)
Definition memory.h:54
#define BROTLI_IS_NULL(A)
Definition memory.h:68
#define HQ_ZOPFLIFICATION_QUALITY
Definition quality.h:20
Buffer split(Buffer &buffer, ZSTD_outBuffer &outBuffer)
Definition Pzstd.cpp:248
Definition block_splitter.h:22
Definition params.h:32
Definition cluster.h:21
Definition memory.h:26
Definition poolTests.c:28
#define BROTLI_RESTRICT
Definition platform.h:105
#define BROTLI_MAX(T, A, B)
#define BROTLI_MIN(T, A, B)
#define BROTLI_DCHECK(x)
Definition platform.h:484
#define BROTLI_UINT32_MAX
Definition types.h:59
lzma_index ** i
Definition index.h:629
lzma_vli id
Filter ID.
Definition filter_common.c:18
uint32_t u32
Definition zstd_decompress.c:62
uint32_t seed
Definition stream_decompress.c:26