Skip to content

Commit

Permalink
Update encoder:
Browse files Browse the repository at this point in the history
 * booleanification
 * integer BR scores, may improve performance if FPU is slow
 * condense speed-quality constants in quality.h
 * code massage to calm down CoverityScan
 * hashers refactoring
 * new hasher - improved speed, compression and reduced memory usage for q:5-9 w:10-16
 * reduced static recources -> binary size
  • Loading branch information
eustas committed Jul 26, 2016
1 parent aa96d64 commit 2048189
Show file tree
Hide file tree
Showing 37 changed files with 12,585 additions and 13,061 deletions.
372 changes: 177 additions & 195 deletions enc/backward_references.c

Large diffs are not rendered by default.

28 changes: 10 additions & 18 deletions enc/backward_references.h
Expand Up @@ -14,6 +14,7 @@
#include "./hash.h"
#include "./memory.h"
#include "./port.h"
#include "./quality.h"

#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
Expand All @@ -23,21 +24,12 @@ extern "C" {
initially the total amount of commands output by previous
CreateBackwardReferences calls, and must be incremented by the amount written
by this call. */
BROTLI_INTERNAL void BrotliCreateBackwardReferences(MemoryManager* m,
size_t num_bytes,
size_t position,
int is_last,
const uint8_t* ringbuffer,
size_t ringbuffer_mask,
const int quality,
const int lgwin,
Hashers* hashers,
int hash_type,
int* dist_cache,
size_t* last_insert_len,
Command* commands,
size_t* num_commands,
size_t* num_literals);
BROTLI_INTERNAL void BrotliCreateBackwardReferences(
MemoryManager* m, size_t num_bytes, size_t position, BROTLI_BOOL is_last,
const uint8_t* ringbuffer, size_t ringbuffer_mask,
const BrotliEncoderParams* params, Hashers* hashers, int* dist_cache,
size_t* last_insert_len, Command* commands, size_t* num_commands,
size_t* num_literals);

typedef struct ZopfliNode {
/* best length to get up to this byte (not including this byte itself)
Expand Down Expand Up @@ -82,9 +74,9 @@ BROTLI_INTERNAL void BrotliInitZopfliNodes(ZopfliNode* array, size_t length);
(3) nodes[i - nodes[i].command_length()].cost < kInfinity */
BROTLI_INTERNAL size_t BrotliZopfliComputeShortestPath(
MemoryManager* m, size_t num_bytes, size_t position,
const uint8_t* ringbuffer, size_t ringbuffer_mask, const int quality,
const size_t max_backward_limit, const int* dist_cache, H10* hasher,
ZopfliNode* nodes);
const uint8_t* ringbuffer, size_t ringbuffer_mask,
const BrotliEncoderParams* params, const size_t max_backward_limit,
const int* dist_cache, H10* hasher, ZopfliNode* nodes);

BROTLI_INTERNAL void BrotliZopfliCreateCommands(const size_t num_bytes,
const size_t block_start,
Expand Down
85 changes: 38 additions & 47 deletions enc/backward_references_inc.h
Expand Up @@ -9,75 +9,66 @@

#define Hasher HASHER()

static void FN(CreateBackwardReferences)(MemoryManager* m,
size_t num_bytes,
size_t position,
int is_last,
const uint8_t* ringbuffer,
size_t ringbuffer_mask,
const int quality,
const int lgwin,
Hasher* hasher,
int* dist_cache,
size_t* last_insert_len,
Command* commands,
size_t* num_commands,
size_t* num_literals) {
static BROTLI_NOINLINE void FN(CreateBackwardReferences)(
MemoryManager* m, size_t num_bytes, size_t position, BROTLI_BOOL is_last,
const uint8_t* ringbuffer, size_t ringbuffer_mask,
const BrotliEncoderParams* params, Hasher* hasher, int* dist_cache,
size_t* last_insert_len, Command* commands, size_t* num_commands,
size_t* num_literals) {
/* Set maximum distance, see section 9.1. of the spec. */
const size_t max_backward_limit = MaxBackwardLimit(lgwin);
const size_t max_backward_limit = MaxBackwardLimit(params->lgwin);

const Command * const orig_commands = commands;
const Command* const orig_commands = commands;
size_t insert_length = *last_insert_len;
const size_t pos_end = position + num_bytes;
const size_t store_end = num_bytes >= FN(StoreLookahead)() ?
position + num_bytes - FN(StoreLookahead)() + 1 : position;

/* For speed up heuristics for random data. */
const size_t random_heuristics_window_size = quality < 9 ? 64 : 512;
const size_t random_heuristics_window_size =
LiteralSpreeLengthForSparseSearch(params);
size_t apply_random_heuristics = position + random_heuristics_window_size;

/* Minimum score to accept a backward reference. */
const double kMinScore = 4.0;
const score_t kMinScore = BROTLI_SCORE_BASE + 400;

FN(Init)(m, hasher, ringbuffer, lgwin, position, num_bytes, is_last);
FN(Init)(m, hasher, ringbuffer, params, position, num_bytes, is_last);
if (BROTLI_IS_OOM(m)) return;
FN(StitchToPreviousBlock)(hasher, num_bytes, position,
ringbuffer, ringbuffer_mask);

while (position + FN(HashTypeLength)() < pos_end) {
size_t max_length = pos_end - position;
size_t max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
size_t best_len = 0;
size_t best_len_code = 0;
size_t best_dist = 0;
double best_score = kMinScore;
int is_match_found = FN(FindLongestMatch)(hasher, ringbuffer,
ringbuffer_mask, dist_cache, position, max_length, max_distance,
&best_len, &best_len_code, &best_dist, &best_score);
if (is_match_found) {
HasherSearchResult sr;
sr.len = 0;
sr.len_x_code = 0;
sr.distance = 0;
sr.score = kMinScore;
if (FN(FindLongestMatch)(hasher, ringbuffer, ringbuffer_mask, dist_cache,
position, max_length, max_distance, &sr)) {
/* Found a match. Let's look for something even better ahead. */
int delayed_backward_references_in_row = 0;
--max_length;
for (;; --max_length) {
size_t best_len_2 =
quality < 5 ? BROTLI_MIN(size_t, best_len - 1, max_length) : 0;
size_t best_len_code_2 = 0;
size_t best_dist_2 = 0;
double best_score_2 = kMinScore;
const double cost_diff_lazy = 7.0;
const score_t cost_diff_lazy = 700;
BROTLI_BOOL is_match_found;
HasherSearchResult sr2;
sr2.len = params->quality < MIN_QUALITY_FOR_EXTENSIVE_REFERENCE_SEARCH ?
BROTLI_MIN(size_t, sr.len - 1, max_length) : 0;
sr2.len_x_code = 0;
sr2.distance = 0;
sr2.score = kMinScore;
max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
is_match_found = FN(FindLongestMatch)(hasher, ringbuffer,
ringbuffer_mask, dist_cache, position + 1, max_length, max_distance,
&best_len_2, &best_len_code_2, &best_dist_2, &best_score_2);
if (is_match_found && best_score_2 >= best_score + cost_diff_lazy) {
&sr2);
if (is_match_found && sr2.score >= sr.score + cost_diff_lazy) {
/* Ok, let's just write one byte for now and start a match from the
next byte. */
++position;
++insert_length;
best_len = best_len_2;
best_len_code = best_len_code_2;
best_dist = best_dist_2;
best_score = best_score_2;
sr = sr2;
if (++delayed_backward_references_in_row < 4 &&
position + FN(HashTypeLength)() < pos_end) {
continue;
Expand All @@ -86,30 +77,30 @@ static void FN(CreateBackwardReferences)(MemoryManager* m,
break;
}
apply_random_heuristics =
position + 2 * best_len + random_heuristics_window_size;
position + 2 * sr.len + random_heuristics_window_size;
max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
{
/* The first 16 codes are special shortcodes,
and the minimum offset is 1. */
size_t distance_code =
ComputeDistanceCode(best_dist, max_distance, quality, dist_cache);
if (best_dist <= max_distance && distance_code > 0) {
ComputeDistanceCode(sr.distance, max_distance, dist_cache);
if (sr.distance <= max_distance && distance_code > 0) {
dist_cache[3] = dist_cache[2];
dist_cache[2] = dist_cache[1];
dist_cache[1] = dist_cache[0];
dist_cache[0] = (int)best_dist;
dist_cache[0] = (int)sr.distance;
}
InitCommand(
commands++, insert_length, best_len, best_len_code, distance_code);
InitCommand(commands++, insert_length, sr.len, sr.len ^ sr.len_x_code,
distance_code);
}
*num_literals += insert_length;
insert_length = 0;
/* Put the hash keys into the table, if there are enough bytes left.
Depending on the hasher implementation, it can push all positions
in the given range or only a subset of them. */
FN(StoreRange)(hasher, ringbuffer, ringbuffer_mask, position + 2,
BROTLI_MIN(size_t, position + best_len, store_end));
position += best_len;
BROTLI_MIN(size_t, position + sr.len, store_end));
position += sr.len;
} else {
++insert_length;
++position;
Expand Down
9 changes: 5 additions & 4 deletions enc/block_splitter.c
Expand Up @@ -18,6 +18,7 @@
#include "./histogram.h"
#include "./memory.h"
#include "./port.h"
#include "./quality.h"

#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
Expand Down Expand Up @@ -127,7 +128,7 @@ void BrotliSplitBlock(MemoryManager* m,
const uint8_t* data,
const size_t pos,
const size_t mask,
const int quality,
const BrotliEncoderParams* params,
BlockSplit* literal_split,
BlockSplit* insert_and_copy_split,
BlockSplit* dist_split) {
Expand All @@ -142,7 +143,7 @@ void BrotliSplitBlock(MemoryManager* m,
SplitByteVectorLiteral(
m, literals, literals_count,
kSymbolsPerLiteralHistogram, kMaxLiteralHistograms,
kLiteralStrideLength, kLiteralBlockSwitchCost, quality,
kLiteralStrideLength, kLiteralBlockSwitchCost, params,
literal_split);
if (BROTLI_IS_OOM(m)) return;
BROTLI_FREE(m, literals);
Expand All @@ -160,7 +161,7 @@ void BrotliSplitBlock(MemoryManager* m,
SplitByteVectorCommand(
m, insert_and_copy_codes, num_commands,
kSymbolsPerCommandHistogram, kMaxCommandHistograms,
kCommandStrideLength, kCommandBlockSwitchCost, quality,
kCommandStrideLength, kCommandBlockSwitchCost, params,
insert_and_copy_split);
if (BROTLI_IS_OOM(m)) return;
/* TODO: reuse for distances? */
Expand All @@ -183,7 +184,7 @@ void BrotliSplitBlock(MemoryManager* m,
SplitByteVectorDistance(
m, distance_prefixes, j,
kSymbolsPerDistanceHistogram, kMaxCommandHistograms,
kCommandStrideLength, kDistanceBlockSwitchCost, quality,
kCommandStrideLength, kDistanceBlockSwitchCost, params,
dist_split);
if (BROTLI_IS_OOM(m)) return;
BROTLI_FREE(m, distance_prefixes);
Expand Down
3 changes: 2 additions & 1 deletion enc/block_splitter.h
Expand Up @@ -13,6 +13,7 @@
#include "./command.h"
#include "./memory.h"
#include "./port.h"
#include "./quality.h"

#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
Expand All @@ -38,7 +39,7 @@ BROTLI_INTERNAL void BrotliSplitBlock(MemoryManager* m,
const uint8_t* data,
const size_t offset,
const size_t mask,
const int quality,
const BrotliEncoderParams* params,
BlockSplit* literal_split,
BlockSplit* insert_and_copy_split,
BlockSplit* dist_split);
Expand Down
15 changes: 8 additions & 7 deletions enc/block_splitter_inc.h
Expand Up @@ -216,6 +216,10 @@ static void FN(ClusterBlocks)(MemoryManager* m,
uint32_t* new_index;
uint8_t max_type = 0;
size_t i;
uint32_t sizes[HISTOGRAMS_PER_BATCH] = { 0 };
uint32_t new_clusters[HISTOGRAMS_PER_BATCH] = { 0 };
uint32_t symbols[HISTOGRAMS_PER_BATCH] = { 0 };
uint32_t remap[HISTOGRAMS_PER_BATCH] = { 0 };

if (BROTLI_IS_OOM(m)) return;

Expand All @@ -236,10 +240,6 @@ static void FN(ClusterBlocks)(MemoryManager* m,
for (i = 0; i < num_blocks; i += HISTOGRAMS_PER_BATCH) {
const size_t num_to_combine =
BROTLI_MIN(size_t, num_blocks - i, HISTOGRAMS_PER_BATCH);
uint32_t sizes[HISTOGRAMS_PER_BATCH];
uint32_t new_clusters[HISTOGRAMS_PER_BATCH];
uint32_t symbols[HISTOGRAMS_PER_BATCH];
uint32_t remap[HISTOGRAMS_PER_BATCH];
size_t num_new_clusters;
size_t j;
for (j = 0; j < num_to_combine; ++j) {
Expand All @@ -249,7 +249,8 @@ static void FN(ClusterBlocks)(MemoryManager* m,
FN(HistogramAdd)(&histograms[j], data[pos++]);
}
histograms[j].bit_cost_ = FN(BrotliPopulationCost)(&histograms[j]);
symbols[j] = new_clusters[j] = (uint32_t)j;
new_clusters[j] = (uint32_t)j;
symbols[j] = (uint32_t)j;
sizes[j] = 1;
}
num_new_clusters = FN(BrotliHistogramCombine)(
Expand Down Expand Up @@ -362,7 +363,7 @@ static void FN(SplitByteVector)(MemoryManager* m,
const size_t max_histograms,
const size_t sampling_stride_length,
const double block_switch_cost,
const int quality,
const BrotliEncoderParams* params,
BlockSplit* split) {
const size_t data_size = FN(HistogramDataSize)();
size_t num_histograms = length / literals_per_histogram + 1;
Expand Down Expand Up @@ -403,7 +404,7 @@ static void FN(SplitByteVector)(MemoryManager* m,
double* cost = BROTLI_ALLOC(m, double, num_histograms);
uint8_t* switch_signal = BROTLI_ALLOC(m, uint8_t, length * bitmaplen);
uint16_t* new_id = BROTLI_ALLOC(m, uint16_t, num_histograms);
const size_t iters = quality <= 10 ? 3 : 10;
const size_t iters = params->quality < HQ_ZOPFLIFICATION_QUALITY ? 3 : 10;
size_t i;
if (BROTLI_IS_OOM(m)) return;
for (i = 0; i < iters; ++i) {
Expand Down
20 changes: 10 additions & 10 deletions enc/brotli_bit_stream.c
Expand Up @@ -129,7 +129,7 @@ static void StoreVarLenUint8(size_t n, size_t* storage_ix, uint8_t* storage) {
/* Stores the compressed meta-block header.
REQUIRES: length > 0
REQUIRES: length <= (1 << 24) */
static void StoreCompressedMetaBlockHeader(int is_final_block,
static void StoreCompressedMetaBlockHeader(BROTLI_BOOL is_final_block,
size_t length,
size_t* storage_ix,
uint8_t* storage) {
Expand Down Expand Up @@ -403,9 +403,9 @@ static void BuildAndStoreHuffmanTree(const uint32_t *histogram,
}
}

static BROTLI_INLINE int SortHuffmanTree(const HuffmanTree* v0,
const HuffmanTree* v1) {
return (v0->total_count_ < v1->total_count_) ? 1 : 0;
static BROTLI_INLINE BROTLI_BOOL SortHuffmanTree(
const HuffmanTree* v0, const HuffmanTree* v1) {
return TO_BROTLI_BOOL(v0->total_count_ < v1->total_count_);
}

void BrotliBuildAndStoreHuffmanTreeFast(MemoryManager* m,
Expand Down Expand Up @@ -716,7 +716,7 @@ static void EncodeContextMap(MemoryManager* m,
++histogram[rle_symbols[i] & kSymbolMask];
}
{
int use_rle = (max_run_length_prefix > 0) ? 1 : 0;
BROTLI_BOOL use_rle = TO_BROTLI_BOOL(max_run_length_prefix > 0);
BrotliWriteBits(1, (uint64_t)use_rle, storage_ix, storage);
if (use_rle) {
BrotliWriteBits(4, max_run_length_prefix - 1, storage_ix, storage);
Expand All @@ -740,7 +740,7 @@ static void EncodeContextMap(MemoryManager* m,
static BROTLI_INLINE void StoreBlockSwitch(BlockSplitCode* code,
const uint32_t block_len,
const uint8_t block_type,
int is_first_block,
BROTLI_BOOL is_first_block,
size_t* storage_ix,
uint8_t* storage) {
size_t typecode = NextBlockTypeCode(&code->type_code_calculator, block_type);
Expand Down Expand Up @@ -945,7 +945,7 @@ void BrotliStoreMetaBlock(MemoryManager* m,
size_t mask,
uint8_t prev_byte,
uint8_t prev_byte2,
int is_last,
BROTLI_BOOL is_last,
uint32_t num_direct_distance_codes,
uint32_t distance_postfix_bits,
ContextType literal_context_mode,
Expand Down Expand Up @@ -1143,7 +1143,7 @@ void BrotliStoreMetaBlockTrivial(MemoryManager* m,
size_t start_pos,
size_t length,
size_t mask,
int is_last,
BROTLI_BOOL is_last,
const Command *commands,
size_t n_commands,
size_t *storage_ix,
Expand Down Expand Up @@ -1197,7 +1197,7 @@ void BrotliStoreMetaBlockFast(MemoryManager* m,
size_t start_pos,
size_t length,
size_t mask,
int is_last,
BROTLI_BOOL is_last,
const Command *commands,
size_t n_commands,
size_t *storage_ix,
Expand Down Expand Up @@ -1284,7 +1284,7 @@ void BrotliStoreMetaBlockFast(MemoryManager* m,

/* This is for storing uncompressed blocks (simple raw storage of
bytes-as-bytes). */
void BrotliStoreUncompressedMetaBlock(int is_final_block,
void BrotliStoreUncompressedMetaBlock(BROTLI_BOOL is_final_block,
const uint8_t * BROTLI_RESTRICT input,
size_t position, size_t mask,
size_t len,
Expand Down

0 comments on commit 2048189

Please sign in to comment.