Commit 0d855bfc authored by Tatsuhiro Tsujikawa's avatar Tatsuhiro Tsujikawa

Faster huffman encoding

parent 6f967c6e
...@@ -29,114 +29,7 @@ ...@@ -29,114 +29,7 @@
#include <stdio.h> #include <stdio.h>
#include "nghttp2_hd.h" #include "nghttp2_hd.h"
#include "nghttp2_net.h"
/*
* Encodes huffman code |sym| into |*dest_ptr|, whose least |rembits|
* bits are not filled yet. The |rembits| must be in range [1, 8],
* inclusive. At the end of the process, the |*dest_ptr| is updated
* and points where next output should be placed. The number of
* unfilled bits in the pointed location is returned.
*/
static ssize_t huff_encode_sym(nghttp2_bufs *bufs, size_t *avail_ptr,
size_t rembits, const nghttp2_huff_sym *sym) {
int rv;
size_t nbits = sym->nbits;
uint32_t code = sym->code;
/* We assume that sym->nbits <= 32 */
if (rembits > nbits) {
nghttp2_bufs_fast_orb_hold(bufs, (uint8_t)(code << (rembits - nbits)));
return (ssize_t)(rembits - nbits);
}
if (rembits == nbits) {
nghttp2_bufs_fast_orb(bufs, (uint8_t)code);
--*avail_ptr;
return 8;
}
nghttp2_bufs_fast_orb(bufs, (uint8_t)(code >> (nbits - rembits)));
--*avail_ptr;
nbits -= rembits;
if (nbits & 0x7) {
/* align code to MSB byte boundary */
code <<= 8 - (nbits & 0x7);
}
if (*avail_ptr < (nbits + 7) / 8) {
/* slow path */
if (nbits > 24) {
rv = nghttp2_bufs_addb(bufs, (uint8_t)(code >> 24));
if (rv != 0) {
return rv;
}
nbits -= 8;
}
if (nbits > 16) {
rv = nghttp2_bufs_addb(bufs, (uint8_t)(code >> 16));
if (rv != 0) {
return rv;
}
nbits -= 8;
}
if (nbits > 8) {
rv = nghttp2_bufs_addb(bufs, (uint8_t)(code >> 8));
if (rv != 0) {
return rv;
}
nbits -= 8;
}
if (nbits == 8) {
rv = nghttp2_bufs_addb(bufs, (uint8_t)code);
if (rv != 0) {
return rv;
}
*avail_ptr = nghttp2_bufs_cur_avail(bufs);
return 8;
}
rv = nghttp2_bufs_addb_hold(bufs, (uint8_t)code);
if (rv != 0) {
return rv;
}
*avail_ptr = nghttp2_bufs_cur_avail(bufs);
return (ssize_t)(8 - nbits);
}
/* fast path, since most code is less than 8 */
if (nbits < 8) {
nghttp2_bufs_fast_addb_hold(bufs, (uint8_t)code);
*avail_ptr = nghttp2_bufs_cur_avail(bufs);
return (ssize_t)(8 - nbits);
}
/* handle longer code path */
if (nbits > 24) {
nghttp2_bufs_fast_addb(bufs, (uint8_t)(code >> 24));
nbits -= 8;
}
if (nbits > 16) {
nghttp2_bufs_fast_addb(bufs, (uint8_t)(code >> 16));
nbits -= 8;
}
if (nbits > 8) {
nghttp2_bufs_fast_addb(bufs, (uint8_t)(code >> 8));
nbits -= 8;
}
if (nbits == 8) {
nghttp2_bufs_fast_addb(bufs, (uint8_t)code);
*avail_ptr = nghttp2_bufs_cur_avail(bufs);
return 8;
}
nghttp2_bufs_fast_addb_hold(bufs, (uint8_t)code);
*avail_ptr = nghttp2_bufs_cur_avail(bufs);
return (ssize_t)(8 - nbits);
}
size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len) { size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len) {
size_t i; size_t i;
...@@ -151,40 +44,60 @@ size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len) { ...@@ -151,40 +44,60 @@ size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len) {
int nghttp2_hd_huff_encode(nghttp2_bufs *bufs, const uint8_t *src, int nghttp2_hd_huff_encode(nghttp2_bufs *bufs, const uint8_t *src,
size_t srclen) { size_t srclen) {
int rv; const nghttp2_huff_sym *sym;
ssize_t rembits = 8; const uint8_t *end = src + srclen;
size_t i; uint64_t code = 0;
uint32_t x;
size_t nbits = 0;
size_t avail; size_t avail;
int rv;
avail = nghttp2_bufs_cur_avail(bufs); avail = nghttp2_bufs_cur_avail(bufs);
for (i = 0; i < srclen; ++i) { for (; src != end;) {
const nghttp2_huff_sym *sym = &huff_sym_table[src[i]]; sym = &huff_sym_table[*src++];
if (rembits == 8) { code |= (uint64_t)sym->code << (32 - nbits);
if (avail) { nbits += sym->nbits;
nghttp2_bufs_fast_addb_hold(bufs, 0); if (nbits < 32) {
} else { continue;
rv = nghttp2_bufs_addb_hold(bufs, 0); }
if (rv != 0) { if (avail >= 4) {
return rv; x = htonl((uint32_t)(code >> 32));
} memcpy(bufs->cur->buf.last, &x, 4);
avail = nghttp2_bufs_cur_avail(bufs); bufs->cur->buf.last += 4;
avail -= 4;
code <<= 32;
nbits -= 32;
continue;
}
for (; nbits >= 8;) {
rv = nghttp2_bufs_addb(bufs, (uint8_t)(code >> 56));
if (rv != 0) {
return rv;
} }
code <<= 8;
nbits -= 8;
} }
rembits = huff_encode_sym(bufs, &avail, (size_t)rembits, sym);
if (rembits < 0) { avail = nghttp2_bufs_cur_avail(bufs);
return (int)rembits; }
for (; nbits >= 8;) {
rv = nghttp2_bufs_addb(bufs, (uint8_t)(code >> 56));
if (rv != 0) {
return rv;
} }
code <<= 8;
nbits -= 8;
} }
/* 256 is special terminal symbol, pad with its prefix */
if (rembits < 8) { if (nbits) {
/* if rembits < 8, we should have at least 1 buffer space rv = nghttp2_bufs_addb(
available */ bufs, (uint8_t)((uint8_t)(code >> 56) | ((1 << (8 - nbits)) - 1)));
const nghttp2_huff_sym *sym = &huff_sym_table[256]; if (rv != 0) {
assert(avail); return rv;
/* Caution we no longer adjust avail here */ }
nghttp2_bufs_fast_orb(
bufs, (uint8_t)(sym->code >> (sym->nbits - (size_t)rembits)));
} }
return 0; return 0;
......
This diff is collapsed.
...@@ -423,9 +423,12 @@ typedef struct { ...@@ -423,9 +423,12 @@ typedef struct {
print '''\ print '''\
const nghttp2_huff_sym huff_sym_table[] = {''' const nghttp2_huff_sym huff_sym_table[] = {'''
for i in range(257): for i in range(257):
nbits = symbol_tbl[i][0]
k = int(symbol_tbl[i][1], 16)
k = k << (32 - nbits)
print '''\ print '''\
{{ {}, 0x{}u }}{}\ {{ {}, 0x{}u }}{}\
'''.format(symbol_tbl[i][0], symbol_tbl[i][1], ',' if i < 256 else '') '''.format(symbol_tbl[i][0], hex(k)[2:], ',' if i < 256 else '')
print '};' print '};'
print '' print ''
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment