/src/cmp_tool/programs/cmp_guess.c
Line | Count | Source (jump to first uncovered line) |
1 | | /** |
2 | | * @file cmp_guess.c |
3 | | * @author Dominik Loidolt (dominik.loidolt@univie.ac.at) |
4 | | * @date 2021 |
5 | | * |
6 | | * @copyright GPLv2 |
7 | | * This program is free software; you can redistribute it and/or modify it |
8 | | * under the terms and conditions of the GNU General Public License, |
9 | | * version 2, as published by the Free Software Foundation. |
10 | | * |
11 | | * This program is distributed in the hope it will be useful, but WITHOUT |
12 | | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 | | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
14 | | * more details. |
15 | | * |
16 | | * @brief helps the user find good compression parameters for a given dataset |
17 | | * @warning this part of the software is not intended to run on-board on the ICU. |
18 | | */ |
19 | | |
20 | | #include <limits.h> |
21 | | #include <stdint.h> |
22 | | #include <stdio.h> |
23 | | #include <stdlib.h> |
24 | | #include <string.h> |
25 | | |
26 | | #include <cmp_error.h> |
27 | | #include <cmp_debug.h> |
28 | | #include <leon_inttypes.h> |
29 | | #include <cmp_data_types.h> |
30 | | #include <cmp_support.h> |
31 | | #include <cmp_icu.h> |
32 | | #include <cmp_chunk.h> |
33 | | #include <cmp_chunk_type.h> |
34 | | #include <cmp_guess.h> |
35 | | |
36 | 0 | #define CMP_GUESS_MAX_CAL_STEPS 20274 |
37 | | |
38 | | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
39 | | /* Redefine (f)printf to do nothing */ |
40 | | __extension__ |
41 | 0 | #define printf(...) do {} while (0) |
42 | 0 | #define fprintf(...) do {} while (0) |
43 | | #endif |
44 | | |
45 | | |
46 | | /* how often the model is updated before it is rested */ |
47 | | static int num_model_updates = CMP_GUESS_N_MODEL_UPDATE_DEF; |
48 | | |
49 | | |
50 | | /** |
51 | | * @brief sets how often the model is updated before the model reset; |
52 | | * @note the default value is CMP_GUESS_N_MODEL_UPDATE_DEF |
53 | | * @note this is needed to guess a good model_value |
54 | | * |
55 | | * @param n_model_updates number of model updates |
56 | | */ |
57 | | |
58 | | void cmp_guess_set_model_updates(int n_model_updates) |
59 | 0 | { |
60 | 0 | num_model_updates = n_model_updates; |
61 | 0 | } |
62 | | |
63 | | |
64 | | /** |
65 | | * @brief guess a good model value |
66 | | * |
67 | | * @param n_model_updates number of model updates |
68 | | * |
69 | | * @returns guessed model_value |
70 | | */ |
71 | | |
72 | | uint16_t cmp_guess_model_value(int n_model_updates) |
73 | 46 | { |
74 | 46 | if (n_model_updates <= 2) |
75 | 0 | return 8; |
76 | 46 | if (n_model_updates <= 5) |
77 | 0 | return 10; |
78 | 46 | if (n_model_updates <= 11) |
79 | 46 | return 11; |
80 | 0 | if (n_model_updates <= 21) |
81 | 0 | return 12; |
82 | | |
83 | 0 | return 13; |
84 | 0 | } |
85 | | |
86 | | |
87 | | /** |
88 | | * @brief get a good spill threshold parameter for the selected Golomb parameter |
89 | | * and compression mode |
90 | | * |
91 | | * @param golomb_par Golomb parameter |
92 | | * @param cmp_mode compression mode |
93 | | * |
94 | | * @returns a good spill parameter (optimal for zero escape mechanism) |
95 | | */ |
96 | | |
97 | | uint32_t cmp_rdcu_get_good_spill(unsigned int golomb_par, enum cmp_mode cmp_mode) |
98 | 2.94k | { |
99 | 2.94k | const uint32_t LUT_IMA_MULIT[MAX_IMA_GOLOMB_PAR+1] = {0, 8, 16, 23, |
100 | 2.94k | 30, 36, 44, 51, 58, 64, 71, 77, 84, 90, 97, 108, 115, 121, 128, |
101 | 2.94k | 135, 141, 148, 155, 161, 168, 175, 181, 188, 194, 201, 207, 214, |
102 | 2.94k | 229, 236, 242, 250, 256, 263, 269, 276, 283, 290, 296, 303, 310, |
103 | 2.94k | 317, 324, 330, 336, 344, 351, 358, 363, 370, 377, 383, 391, 397, |
104 | 2.94k | 405, 411, 418, 424, 431, 452 }; |
105 | | |
106 | 2.94k | if (zero_escape_mech_is_used(cmp_mode)) |
107 | 1.60k | return cmp_ima_max_spill(golomb_par); |
108 | | |
109 | 1.34k | if (cmp_mode == CMP_MODE_MODEL_MULTI) { |
110 | 576 | if (golomb_par > MAX_IMA_GOLOMB_PAR) |
111 | 0 | return 0; |
112 | 576 | else |
113 | 576 | return LUT_IMA_MULIT[golomb_par]; |
114 | 576 | } |
115 | | |
116 | 768 | if (cmp_mode == CMP_MODE_DIFF_MULTI) |
117 | 576 | return CMP_GOOD_SPILL_DIFF_MULTI; |
118 | | |
119 | 192 | return 0; |
120 | 768 | } |
121 | | |
122 | | |
123 | | /** |
124 | | * @brief guess a good configuration with pre_cal_method |
125 | | * |
126 | | * @param rcfg RDCU compression configuration structure |
127 | | * |
128 | | * @returns the size in bits of the compressed data of the guessed |
129 | | * configuration; 0 on error |
130 | | */ |
131 | | |
132 | | static uint32_t pre_cal_method(struct rdcu_cfg *rcfg) |
133 | 46 | { |
134 | 46 | uint32_t g; |
135 | 46 | uint32_t cmp_size, cmp_size_best = INT_MAX; |
136 | 46 | uint32_t golomb_par_best = 0; |
137 | 46 | uint32_t spill_best = 0; |
138 | | |
139 | 2.89k | for (g = MIN_IMA_GOLOMB_PAR; g < MAX_IMA_GOLOMB_PAR; g++) { |
140 | 2.85k | uint32_t s = cmp_rdcu_get_good_spill(g, rcfg->cmp_mode); |
141 | | |
142 | 2.85k | rcfg->golomb_par = g; |
143 | 2.85k | rcfg->spill = s; |
144 | 2.85k | cmp_size = compress_like_rdcu(rcfg, NULL); |
145 | 2.85k | if (cmp_is_error(cmp_size)) { |
146 | 0 | return 0; |
147 | 2.85k | } else if (cmp_size < cmp_size_best) { |
148 | 231 | cmp_size_best = cmp_size; |
149 | 231 | golomb_par_best = g; |
150 | 231 | spill_best = s; |
151 | 231 | } |
152 | 2.85k | } |
153 | 46 | rcfg->golomb_par = golomb_par_best; |
154 | 46 | rcfg->spill = spill_best; |
155 | | |
156 | 46 | return cmp_size_best; |
157 | 46 | } |
158 | | |
159 | | |
160 | | /** |
161 | | * @brief guess a good configuration with brute force method |
162 | | * |
163 | | * @param rcfg RDCU compression configuration structure |
164 | | * |
165 | | * @returns the size in bits of the compressed data of the guessed |
166 | | * configuration; 0 on error |
167 | | */ |
168 | | |
169 | | static uint32_t brute_force(struct rdcu_cfg *rcfg) |
170 | 0 | { |
171 | 0 | uint32_t g, s; |
172 | 0 | uint32_t n_cal_steps = 0, last = 0; |
173 | 0 | const uint32_t max_cal_steps = CMP_GUESS_MAX_CAL_STEPS; |
174 | 0 | uint32_t cmp_size, cmp_size_best = INT_MAX; |
175 | 0 | uint32_t golomb_par_best = 0; |
176 | 0 | uint32_t spill_best = 0; |
177 | 0 | uint32_t percent; |
178 | | |
179 | | /* shortcut for zero escape mechanism */ |
180 | 0 | if (zero_escape_mech_is_used(rcfg->cmp_mode)) |
181 | 0 | return pre_cal_method(rcfg); |
182 | | |
183 | 0 | printf("0%%... "); |
184 | 0 | fflush(stdout); |
185 | |
|
186 | 0 | for (g = MIN_IMA_GOLOMB_PAR; g < MAX_IMA_GOLOMB_PAR; g++) { |
187 | 0 | for (s = MIN_IMA_SPILL; s < cmp_ima_max_spill(g); s++) { |
188 | 0 | rcfg->golomb_par = g; |
189 | 0 | rcfg->spill = s; |
190 | |
|
191 | 0 | cmp_size = compress_like_rdcu(rcfg, NULL); |
192 | 0 | if (cmp_is_error(cmp_size)) { |
193 | 0 | return 0; |
194 | 0 | } else if (cmp_size < cmp_size_best) { |
195 | 0 | cmp_size_best = cmp_size; |
196 | 0 | golomb_par_best = g; |
197 | 0 | spill_best = s; |
198 | 0 | } |
199 | 0 | } |
200 | 0 | n_cal_steps += s; |
201 | |
|
202 | 0 | percent = n_cal_steps*100/max_cal_steps; |
203 | 0 | if (percent > 5+last && percent < 100) { |
204 | 0 | last = percent; |
205 | 0 | printf("%" PRIu32 "%%... ", percent); |
206 | 0 | fflush(stdout); |
207 | 0 | } |
208 | 0 | } |
209 | 0 | printf("100%% "); |
210 | 0 | rcfg->golomb_par = golomb_par_best; |
211 | 0 | rcfg->spill = spill_best; |
212 | |
|
213 | 0 | return cmp_size_best; |
214 | 0 | } |
215 | | |
216 | | |
217 | | /** |
218 | | * @brief guessed rdcu specific adaptive parameters |
219 | | * |
220 | | * @param rcfg RDCU compression configuration structure |
221 | | * @note internal use only |
222 | | */ |
223 | | |
224 | | static void add_rdcu_pars_internal(struct rdcu_cfg *rcfg) |
225 | 46 | { |
226 | 46 | if (rcfg->golomb_par == MIN_IMA_GOLOMB_PAR) { |
227 | 17 | rcfg->ap1_golomb_par = rcfg->golomb_par + 1; |
228 | 17 | rcfg->ap2_golomb_par = rcfg->golomb_par + 2; |
229 | | |
230 | 29 | } else if (rcfg->golomb_par == MAX_IMA_GOLOMB_PAR) { |
231 | 0 | rcfg->ap1_golomb_par = rcfg->golomb_par - 2; |
232 | 0 | rcfg->ap2_golomb_par = rcfg->golomb_par - 1; |
233 | 29 | } else { |
234 | 29 | rcfg->ap1_golomb_par = rcfg->golomb_par - 1; |
235 | 29 | rcfg->ap2_golomb_par = rcfg->golomb_par + 1; |
236 | 29 | } |
237 | | |
238 | 46 | rcfg->ap1_spill = cmp_rdcu_get_good_spill(rcfg->ap1_golomb_par, rcfg->cmp_mode); |
239 | 46 | rcfg->ap2_spill = cmp_rdcu_get_good_spill(rcfg->ap2_golomb_par, rcfg->cmp_mode); |
240 | | |
241 | 46 | if (model_mode_is_used(rcfg->cmp_mode)) { |
242 | 16 | rcfg->rdcu_data_adr = CMP_DEF_IMA_MODEL_RDCU_DATA_ADR; |
243 | 16 | rcfg->rdcu_model_adr = CMP_DEF_IMA_MODEL_RDCU_MODEL_ADR; |
244 | 16 | rcfg->rdcu_new_model_adr = CMP_DEF_IMA_MODEL_RDCU_UP_MODEL_ADR; |
245 | 16 | rcfg->rdcu_buffer_adr = CMP_DEF_IMA_MODEL_RDCU_BUFFER_ADR; |
246 | 30 | } else { |
247 | 30 | rcfg->rdcu_data_adr = CMP_DEF_IMA_DIFF_RDCU_DATA_ADR; |
248 | 30 | rcfg->rdcu_model_adr = CMP_DEF_IMA_DIFF_RDCU_MODEL_ADR; |
249 | 30 | rcfg->rdcu_new_model_adr = CMP_DEF_IMA_DIFF_RDCU_UP_MODEL_ADR; |
250 | 30 | rcfg->rdcu_buffer_adr = CMP_DEF_IMA_DIFF_RDCU_BUFFER_ADR; |
251 | 30 | } |
252 | 46 | } |
253 | | |
254 | | |
255 | | /** |
256 | | * @brief guess a good compression configuration |
257 | | * @details use the samples, input_buf, model_buf and the cmp_mode in rcfg to |
258 | | * find a good set of compression parameters |
259 | | * @note compression parameters in the rcfg struct (golomb_par, spill, model_value, |
260 | | * ap1_.., ap2_.., buffer_length, ...) are overwritten by this function |
261 | | * |
262 | | * @param rcfg RDCU compression configuration structure |
263 | | * @param level guess_level 1 -> fast; 2 -> default; 3 -> slow(brute force) |
264 | | * |
265 | | * @returns the size in bits of the compressed data of the guessed |
266 | | * configuration; 0 on error |
267 | | */ |
268 | | |
269 | | uint32_t cmp_guess(struct rdcu_cfg *rcfg, int level) |
270 | 46 | { |
271 | 46 | struct rdcu_cfg work_rcfg; |
272 | 46 | uint32_t cmp_size = 0; |
273 | | |
274 | 46 | if (!rcfg) |
275 | 0 | return 0; |
276 | | |
277 | 46 | if (!rcfg->input_buf) |
278 | 0 | return 0; |
279 | 46 | if (model_mode_is_used(rcfg->cmp_mode)) |
280 | 16 | if (!rcfg->model_buf) |
281 | 0 | return 0; |
282 | | |
283 | 46 | if (!cmp_mode_is_supported(rcfg->cmp_mode)) { |
284 | 0 | printf("This compression mode is not implied yet.\n"); |
285 | 0 | return 0; |
286 | 0 | } |
287 | | /* make a working copy of the input data (and model) because the |
288 | | * following function works in-place |
289 | | */ |
290 | 46 | work_rcfg = *rcfg; |
291 | 46 | work_rcfg.icu_new_model_buf = NULL; |
292 | 46 | work_rcfg.icu_output_buf = NULL; |
293 | 46 | work_rcfg.buffer_length = 0; |
294 | | |
295 | 46 | if (model_mode_is_used(rcfg->cmp_mode)) { |
296 | 16 | work_rcfg.icu_new_model_buf = malloc(rcfg->samples * sizeof(uint16_t)); |
297 | 16 | if (!work_rcfg.icu_new_model_buf) { |
298 | 0 | printf("malloc() failed!\n"); |
299 | 0 | goto error; |
300 | 0 | } |
301 | 16 | } |
302 | | |
303 | | /* find the best parameters */ |
304 | 46 | switch (level) { |
305 | 0 | case 3: |
306 | 0 | cmp_size = brute_force(&work_rcfg); |
307 | 0 | break; |
308 | 0 | case 1: |
309 | 0 | printf("guess level 1 not implied for RDCU data, I use guess level 2\n"); |
310 | | /* fall through */ |
311 | 46 | case 2: |
312 | 46 | cmp_size = pre_cal_method(&work_rcfg); |
313 | 46 | break; |
314 | 0 | default: |
315 | 0 | fprintf(stderr, "cmp_tool: guess level not supported for RDCU guess mode!\n"); |
316 | 0 | goto error; |
317 | 46 | } |
318 | 46 | if (!cmp_size) |
319 | 0 | goto error; |
320 | | |
321 | 46 | free(work_rcfg.icu_new_model_buf); |
322 | | |
323 | 46 | rcfg->golomb_par = work_rcfg.golomb_par; |
324 | 46 | rcfg->spill = work_rcfg.spill; |
325 | | |
326 | 46 | rcfg->model_value = cmp_guess_model_value(num_model_updates); |
327 | | |
328 | 46 | add_rdcu_pars_internal(rcfg); |
329 | | |
330 | 46 | rcfg->buffer_length = ((cmp_size + 32)&~0x1FU)/(size_of_a_sample(DATA_TYPE_IMAGETTE)*8); |
331 | | |
332 | 46 | return cmp_size; |
333 | | |
334 | 0 | error: |
335 | 0 | free(work_rcfg.icu_new_model_buf); |
336 | 0 | return 0; |
337 | 46 | } |
338 | | |
339 | | |
340 | | /** |
341 | | * @brief get the next Golomb parameter value to try based on the guess level |
342 | | * |
343 | | * @param cur_g current Golomb parameter value |
344 | | * @param guess_level determines the granularity of the parameter search |
345 | | * higher values decrease step size (finer search) |
346 | | * lower/negative values increase step size (coarser search) |
347 | | * range: [-31, 31], default: 2 |
348 | | * |
349 | | * @returns next Golomb parameter value to try |
350 | | */ |
351 | | |
352 | | static uint32_t get_next_g_par(uint32_t cur_g, int guess_level) |
353 | 0 | { |
354 | 0 | uint32_t result = cur_g; |
355 | |
|
356 | 0 | guess_level--; /* use a better guess level */ |
357 | |
|
358 | 0 | if (guess_level > 31) |
359 | 0 | guess_level = 31; |
360 | |
|
361 | 0 | if (guess_level < -31) |
362 | 0 | guess_level = -31; |
363 | | |
364 | |
|
365 | 0 | if (guess_level >= 0) |
366 | 0 | result += (1U << ilog_2(cur_g)) >> guess_level; |
367 | 0 | else |
368 | 0 | result = cur_g << -guess_level; |
369 | |
|
370 | 0 | if (result == cur_g) |
371 | 0 | result++; |
372 | |
|
373 | 0 | return result; |
374 | 0 | } |
375 | | |
376 | | |
377 | | /** |
378 | | * @brief estimate the optimal specific compression parameter set for a given chunk type |
379 | | * |
380 | | * @param chunk pointer to the chunk data to analyse |
381 | | * @param chunk_size size of the chunk in bytes |
382 | | * @param chunk_model pointer to the model data (can be NULL) |
383 | | * @param cmp_par pointer to where to store the optimized compression parameters |
384 | | * @param guess_level controls the granularity of the parameter search; 2 is the default |
385 | | * |
386 | | * @returns the size of the compressed data with the estimated parameters; error |
387 | | * code on failure |
388 | | */ |
389 | | |
390 | | static uint32_t cmp_guess_chunk_par(const void *chunk, uint32_t chunk_size, |
391 | | const void *chunk_model, struct cmp_par *cmp_par, |
392 | | int guess_level) |
393 | 0 | { |
394 | 0 | uint32_t *param_ptrs[7] = {0}; |
395 | 0 | uint32_t cmp_size_best = ~0U; |
396 | 0 | int i; |
397 | |
|
398 | 0 | if (cmp_par->lossy_par) |
399 | 0 | debug_print("Warning: lossy compression is not supported for chunk compression, lossy_par will be ignored."); |
400 | 0 | cmp_par->lossy_par = 0; |
401 | 0 | cmp_par->model_value = cmp_guess_model_value(num_model_updates); |
402 | |
|
403 | 0 | switch (cmp_col_get_chunk_type(chunk)) { |
404 | 0 | case CHUNK_TYPE_NCAM_IMAGETTE: |
405 | 0 | param_ptrs[0] = &cmp_par->nc_imagette; |
406 | 0 | break; |
407 | 0 | case CHUNK_TYPE_SAT_IMAGETTE: |
408 | 0 | param_ptrs[0] = &cmp_par->saturated_imagette; |
409 | 0 | break; |
410 | 0 | case CHUNK_TYPE_SHORT_CADENCE: |
411 | 0 | param_ptrs[0] = &cmp_par->s_exp_flags; |
412 | 0 | param_ptrs[1] = &cmp_par->s_fx; |
413 | 0 | param_ptrs[2] = &cmp_par->s_ncob; |
414 | 0 | param_ptrs[3] = &cmp_par->s_efx; |
415 | 0 | param_ptrs[4] = &cmp_par->s_ecob; |
416 | 0 | break; |
417 | 0 | case CHUNK_TYPE_LONG_CADENCE: |
418 | 0 | param_ptrs[0] = &cmp_par->l_exp_flags; |
419 | 0 | param_ptrs[1] = &cmp_par->l_fx; |
420 | 0 | param_ptrs[2] = &cmp_par->l_ncob; |
421 | 0 | param_ptrs[3] = &cmp_par->l_efx; |
422 | 0 | param_ptrs[4] = &cmp_par->l_ecob; |
423 | 0 | param_ptrs[5] = &cmp_par->l_fx_cob_variance; |
424 | 0 | break; |
425 | 0 | case CHUNK_TYPE_OFFSET_BACKGROUND: |
426 | 0 | param_ptrs[0] = &cmp_par->nc_offset_mean; |
427 | 0 | param_ptrs[1] = &cmp_par->nc_offset_variance; |
428 | 0 | param_ptrs[2] = &cmp_par->nc_background_mean; |
429 | 0 | param_ptrs[3] = &cmp_par->nc_background_variance; |
430 | 0 | param_ptrs[4] = &cmp_par->nc_background_outlier_pixels; |
431 | 0 | break; |
432 | 0 | case CHUNK_TYPE_SMEARING: |
433 | 0 | param_ptrs[0] = &cmp_par->smearing_mean; |
434 | 0 | param_ptrs[1] = &cmp_par->smearing_variance_mean; |
435 | 0 | param_ptrs[2] = &cmp_par->smearing_outlier_pixels; |
436 | 0 | break; |
437 | 0 | case CHUNK_TYPE_F_CHAIN: |
438 | 0 | param_ptrs[0] = &cmp_par->fc_imagette; |
439 | 0 | param_ptrs[1] = &cmp_par->fc_offset_mean; |
440 | 0 | param_ptrs[2] = &cmp_par->fc_offset_variance; |
441 | 0 | param_ptrs[3] = &cmp_par->fc_background_mean; |
442 | 0 | param_ptrs[4] = &cmp_par->fc_background_variance; |
443 | 0 | param_ptrs[5] = &cmp_par->fc_background_outlier_pixels; |
444 | 0 | break; |
445 | 0 | case CHUNK_TYPE_UNKNOWN: |
446 | 0 | default: /* |
447 | | * default case never reached because cmp_col_get_chunk_type |
448 | | * returns CHUNK_TYPE_UNKNOWN if the type is unknown |
449 | | */ |
450 | 0 | break; |
451 | 0 | } |
452 | | |
453 | | /* init */ |
454 | 0 | for (i = 0; param_ptrs[i] != NULL; i++) |
455 | 0 | *param_ptrs[i] = 1; |
456 | |
|
457 | 0 | for (i = 0; param_ptrs[i] != NULL; i++) { |
458 | 0 | uint32_t best_g = *param_ptrs[i]; |
459 | 0 | uint32_t g; |
460 | |
|
461 | 0 | for (g = MIN_NON_IMA_GOLOMB_PAR; g < MAX_NON_IMA_GOLOMB_PAR; g = get_next_g_par(g, guess_level)) { |
462 | 0 | uint32_t cmp_size; |
463 | |
|
464 | 0 | *param_ptrs[i] = g; |
465 | 0 | cmp_size = compress_chunk(chunk, chunk_size, chunk_model, |
466 | 0 | NULL, NULL, 0, cmp_par); |
467 | 0 | FORWARD_IF_ERROR(cmp_size, ""); |
468 | 0 | if (cmp_size < cmp_size_best) { |
469 | 0 | cmp_size_best = cmp_size; |
470 | 0 | best_g = g; |
471 | 0 | } |
472 | 0 | } |
473 | 0 | *param_ptrs[i] = best_g; |
474 | 0 | } |
475 | | |
476 | 0 | return cmp_size_best; |
477 | 0 | } |
478 | | |
479 | | |
480 | | /** |
481 | | * @brief estimate an optimal compression parameters for the given chunk |
482 | | * |
483 | | * @param chunk pointer to the chunk data to analyse |
484 | | * @param chunk_size size of the chunk in bytes |
485 | | * @param chunk_model pointer to the model data (can be NULL) |
486 | | * @param cmp_par pointer to where to store the optimized compression parameters |
487 | | * @param guess_level controls the granularity of the parameter search; 2 is |
488 | | * the default |
489 | | * |
490 | | * @returns the size of the compressed data with the estimated parameters; error |
491 | | * code on failure |
492 | | */ |
493 | | |
494 | | uint32_t cmp_guess_chunk(const void *chunk, uint32_t chunk_size, |
495 | | const void *chunk_model, struct cmp_par *cmp_par, |
496 | | int guess_level) |
497 | 0 | { |
498 | 0 | uint32_t cmp_size_zero, cmp_size_multi; |
499 | 0 | struct cmp_par cmp_par_zero; |
500 | 0 | struct cmp_par cmp_par_multi; |
501 | |
|
502 | 0 | memset(&cmp_par_zero, 0, sizeof(cmp_par_zero)); |
503 | 0 | memset(&cmp_par_multi, 0, sizeof(cmp_par_multi)); |
504 | |
|
505 | 0 | if (chunk_model) { |
506 | 0 | cmp_par_zero.cmp_mode = CMP_MODE_DIFF_ZERO; |
507 | 0 | cmp_par_multi.cmp_mode = CMP_MODE_MODEL_MULTI; |
508 | 0 | } else { |
509 | 0 | cmp_par_zero.cmp_mode = CMP_MODE_DIFF_ZERO; |
510 | 0 | cmp_par_multi.cmp_mode = CMP_MODE_DIFF_MULTI; |
511 | 0 | } |
512 | 0 | cmp_size_zero = cmp_guess_chunk_par(chunk, chunk_size, chunk_model, |
513 | 0 | &cmp_par_zero, guess_level); |
514 | 0 | FORWARD_IF_ERROR(cmp_size_zero, ""); |
515 | | |
516 | 0 | cmp_size_multi = cmp_guess_chunk_par(chunk, chunk_size, chunk_model, |
517 | 0 | &cmp_par_multi, guess_level); |
518 | 0 | FORWARD_IF_ERROR(cmp_size_multi, ""); |
519 | | |
520 | 0 | if (cmp_size_zero <= cmp_size_multi) { |
521 | 0 | *cmp_par = cmp_par_zero; |
522 | 0 | return cmp_size_zero; |
523 | 0 | } |
524 | | |
525 | 0 | *cmp_par = cmp_par_multi; |
526 | 0 | return cmp_size_multi; |
527 | 0 | } |