Skip to content

Commit 845ba21

Browse files
Imrove memory usage during huffman decoding
- Do not allocate new memory during hpack decoding if some memory is already available. (It can be available because we allocate 150 % memory for each header). - Move BUFFER_GET macros to hpack.c - Some codestyle fixes according checkpatch.pl
1 parent d5d2729 commit 845ba21

File tree

3 files changed

+95
-59
lines changed

3 files changed

+95
-59
lines changed

fw/hpack.c

Lines changed: 87 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,31 @@
3030

3131
#include "hpack_tbl.h"
3232

33+
/**
34+
* There are to cases when we allocate space for header:
35+
* - it->rspace is equal to zero. In this case we allocate
36+
* `len` bytes;
37+
* - it->rspace is not equal to zero. This means that we
38+
* already have buffer with rspace bytes available.
39+
* Save delta = len - it->rspace bytes. Later when
40+
* `it->rspace` will be exceeded we use it to
41+
* allocate new chunk;
42+
*/
43+
#define BUFFER_GET(len, it) \
44+
do { \
45+
BUG_ON(!(len)); \
46+
if (!(it)->rspace) { \
47+
(it)->rspace = len; \
48+
(it)->pos = tfw_pool_alloc_not_align((it)->pool, len); \
49+
T_DBG3("%s: get buffer, len=%lu, it->pos=[%p]," \
50+
" it->pos=%lu\n", __func__, (unsigned long)len, \
51+
(it)->pos, (unsigned long)(it)->pos); \
52+
} else { \
53+
(it)->to_alloc = len > (it)->rspace ? \
54+
len - (it)->rspace : 0; \
55+
} \
56+
} while (0)
57+
3358
#define HP_HDR_NAME(name) \
3459
(&(TfwStr){ \
3560
.chunks = &(TfwStr){ \
@@ -278,25 +303,32 @@ do { \
278303
last - src); \
279304
} while (0)
280305

281-
#define BUFFER_HDR_INIT(length, it) \
306+
#define BUFFER_HDR_INIT(it) \
282307
do { \
283308
(it)->hdr.data = (it)->pos; \
284-
(it)->hdr.len = length; \
309+
(it)->hdr.len = 0; \
285310
(it)->next = &(it)->hdr; \
286311
} while (0)
287312

288313
#define BUFFER_NAME_OPEN(length) \
289314
do { \
290315
WARN_ON_ONCE(!TFW_STR_EMPTY(&it->hdr)); \
291316
if (state & HPACK_FLAGS_HUFFMAN_NAME) { \
317+
/* \
318+
* Allocate extra 50% bytes. Huffman usually \
319+
* gives compression benefit about 20 - 60 %. \
320+
* Since we use extra allocated bytes for the \
321+
* next header, we can allocate extra 50% bytes \
322+
* without fear of losing a lot of memory. \
323+
*/ \
292324
unsigned long len = length + (length >> 1); \
293325
\
294326
BUFFER_GET(len, it); \
295327
if (!it->pos) { \
296328
r = -ENOMEM; \
297329
goto out; \
298330
} \
299-
BUFFER_HDR_INIT(len, it); \
331+
BUFFER_HDR_INIT(it); \
300332
} \
301333
} while (0)
302334

@@ -308,6 +340,13 @@ do { \
308340
? it->parsed_hdr->nchunks \
309341
: 1; \
310342
if (state & HPACK_FLAGS_HUFFMAN_VALUE) { \
343+
/* \
344+
* Allocate extra 50% bytes. Huffman usually \
345+
* gives compression benefit about 20 - 60 %. \
346+
* Since we use extra allocated bytes for the \
347+
* next header, we can allocate extra 50% bytes \
348+
* without fear of losing a lot of memory. \
349+
*/ \
311350
unsigned long len = length + (length >> 1); \
312351
\
313352
BUFFER_GET(len, it); \
@@ -317,13 +356,13 @@ do { \
317356
} \
318357
if (!TFW_STR_EMPTY(&it->hdr)) { \
319358
it->next = tfw_hpack_exp_hdr(req->pool, \
320-
len, it); \
359+
0, it); \
321360
if (!it->next) { \
322361
r = -ENOMEM; \
323362
goto out; \
324363
} \
325364
} else { \
326-
BUFFER_HDR_INIT(len, it); \
365+
BUFFER_HDR_INIT(it); \
327366
} \
328367
} \
329368
} while (0)
@@ -459,38 +498,61 @@ tfw_hpack_exp_hdr(TfwPool *__restrict pool, unsigned long len,
459498
static inline int
460499
tfw_hpack_huffman_write(char sym, TfwHttpReq *__restrict req)
461500
{
462-
bool np;
463501
TfwMsgParseIter *it = &req->pit;
502+
unsigned long to_alloc;
503+
bool np;
504+
505+
#define ADJUST_HDR_LEN(it) \
506+
do { \
507+
TfwStr *hdr = &it->hdr; \
508+
TfwStr *last = TFW_STR_LAST(hdr); \
509+
\
510+
T_DBG3("%s: add to hdr, hdr->len=%lu, last->len=%lu," \
511+
" last->data=%.*s\n", __func__, hdr->len, last->len, \
512+
(int)last->len, last->data); \
513+
\
514+
++hdr->len; \
515+
if (!TFW_STR_PLAIN(hdr)) \
516+
++last->len; \
517+
} while (0)
464518

465519
if (it->rspace) {
466520
--it->rspace;
467521
*it->pos++ = sym;
522+
ADJUST_HDR_LEN(it);
468523
return 0;
469524
}
470525

471-
if (!(it->pos = tfw_pool_alloc_not_align_np(it->pool, 1, &np)))
472-
return -ENOMEM;
526+
to_alloc = it->to_alloc ? it->to_alloc : 1;
527+
if (to_alloc > 1)
528+
it->rspace = to_alloc - 1;
473529

474-
*it->pos = sym;
530+
it->pos = tfw_pool_alloc_not_align_np(it->pool, to_alloc, &np);
531+
if (!it->pos)
532+
return -ENOMEM;
475533

476534
T_DBG3("%s: it->rspace=%lu, sym=%c, np=%d\n", __func__,
477535
it->rspace, sym, np);
478536

479-
if (!np) {
480-
TfwStr *hdr = &it->hdr;
481-
TfwStr *last = TFW_STR_LAST(hdr);
482-
483-
T_DBG3("%s: add to hdr, hdr->len=%lu, last->len=%lu,"
484-
" last->data=%.*s\n", __func__, hdr->len, last->len,
485-
(int)last->len, last->data);
486-
487-
++hdr->len;
488-
if (!TFW_STR_PLAIN(hdr))
489-
++last->len;
537+
/*
538+
* If the new page was allocated or it->pos points to
539+
* the buffer, which was allocated to store previously
540+
* decoded header (it->to_alloc != 0) we should expand
541+
* header.
542+
*/
543+
if (!np && !it->to_alloc) {
544+
*it->pos++ = sym;
545+
ADJUST_HDR_LEN(it);
490546
return 0;
491547
}
492548

493-
return tfw_hpack_exp_hdr(req->pool, 1, it) ? 0 : -ENOMEM;
549+
if (!tfw_hpack_exp_hdr(req->pool, 1, it))
550+
return -ENOMEM;
551+
552+
*it->pos++ = sym;
553+
it->to_alloc = 0;
554+
555+
return 0;
494556
}
495557

496558
static int
@@ -501,28 +563,14 @@ huffman_decode_tail(TfwHPack *__restrict hp, TfwHttpReq *__restrict req,
501563
unsigned int i;
502564
int r;
503565

504-
#define ADJUST_EXTRA_RSPACE(req) \
505-
do { \
506-
TfwMsgParseIter *it = &req->pit; \
507-
TfwStr *hdr = &it->hdr; \
508-
TfwStr *last = TFW_STR_LAST(hdr); \
509-
\
510-
hdr->len -= it->rspace; \
511-
if (!TFW_STR_PLAIN(hdr)) \
512-
last->len -= it->rspace; \
513-
it->rspace = 0; \
514-
} while (0)
515-
516566
for (;;) {
517567
int shift;
518568

519569
if (hp->curr == -HT_NBITS) {
520-
if (likely(offset == 0)) {
521-
ADJUST_EXTRA_RSPACE(req);
570+
if (likely(offset == 0))
522571
return T_OK;
523-
} else {
572+
else
524573
return T_COMPRESSION;
525-
}
526574
}
527575

528576
i = (hp->hctx << -hp->curr) & HT_NMASK;
@@ -549,10 +597,8 @@ do { \
549597
*/
550598
if (likely(offset == 0)) {
551599
if ((i ^ (HT_EOS_HIGH >> 1)) <
552-
(1U << -hp->curr)) {
553-
ADJUST_EXTRA_RSPACE(req);
600+
(1U << -hp->curr))
554601
return T_OK;
555-
}
556602
}
557603
/*
558604
* The first condition here equivalent to the
@@ -576,10 +622,8 @@ do { \
576622
}
577623
}
578624
if (likely(offset == 0)) {
579-
if ((i ^ (HT_EOS_HIGH >> 1)) < (1U << -hp->curr)) {
580-
ADJUST_EXTRA_RSPACE(req);
625+
if ((i ^ (HT_EOS_HIGH >> 1)) < (1U << -hp->curr))
581626
return T_OK;
582-
}
583627
}
584628
return T_COMPRESSION;
585629

fw/hpack.h

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -296,17 +296,6 @@ typedef struct {
296296
TfwStr hdr_data;
297297
} TfwDecodeCacheIter;
298298

299-
#define BUFFER_GET(len, it) \
300-
do { \
301-
BUG_ON(!(len)); \
302-
WARN_ON_ONCE((it)->rspace); \
303-
(it)->rspace = len; \
304-
(it)->pos = tfw_pool_alloc_not_align((it)->pool, len); \
305-
T_DBG3("%s: get buffer, len=%lu, it->pos=[%p]," \
306-
" it->pos=%lu\n", __func__, (unsigned long)len, \
307-
(it)->pos, (unsigned long)(it)->pos); \
308-
} while (0)
309-
310299
void write_int(unsigned long index, unsigned short max, unsigned short mask,
311300
TfwHPackInt *__restrict res_idx);
312301
int tfw_hpack_init(TfwHPack *__restrict hp, unsigned int htbl_sz);

fw/msg.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,30 +67,33 @@ typedef struct {
6767
* @pool - allocation pool for target buffer of decoded headers;
6868
* @parsed_hdr - pointer to the message header which is currently processed;
6969
* @hdrs_len - accumulated length of message's decoded and parsed headers;
70+
* @rspace - space remained in the allocated chunk;
71+
* @pos - pointer to the currently allocated chunk of decoded headers'
72+
* buffer;
7073
* @hdrs_cnt - count of all headers from message headers block;
7174
* @__off - offset for iterator reinitializing before next processing
7275
* stage;
7376
* @hdr - descriptor of currently decoded header in target buffer;
74-
* @pos - pointer to the currently allocated chunk of decoded headers'
75-
* buffer;
76-
* @rspace - space remained in the allocated chunk;
7777
* @next - pointer to the decoded header part (name/value) to be
7878
* - parsed next;
7979
* @nm_len - length of the decoded header's name;
80+
* @to_alloc - count of bytes which, should be allocated, after rspace
81+
* will be exceeded;
8082
* @nm_num - chunks number of the decoded header's name;
8183
* @tag - tag of currently processed decoded header.
8284
*/
8385
typedef struct {
8486
TfwPool *pool;
8587
TfwStr *parsed_hdr;
8688
unsigned long hdrs_len;
89+
unsigned long rspace;
90+
char *pos;
8791
unsigned int hdrs_cnt;
8892
char __off[0];
8993
TfwStr hdr;
90-
char *pos;
91-
unsigned long rspace;
9294
TfwStr *next;
9395
unsigned long nm_len;
96+
unsigned long to_alloc;
9497
unsigned int nm_num;
9598
unsigned int tag;
9699
} TfwMsgParseIter;

0 commit comments

Comments
 (0)