Skip to content

Commit ee8b2c0

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 05ca2f2 commit ee8b2c0

File tree

3 files changed

+90
-58
lines changed

3 files changed

+90
-58
lines changed

fw/hpack.c

Lines changed: 82 additions & 42 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 = 0; \
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); \
@@ -316,13 +355,12 @@ do { \
316355
goto out; \
317356
} \
318357
if (!TFW_STR_EMPTY(&it->hdr)) { \
319-
r = tfw_hpack_exp_hdr(req->pool, len, \
320-
it); \
358+
r = tfw_hpack_exp_hdr(req->pool, 0, it); \
321359
if (unlikely(r)) \
322360
return r; \
323361
it->next = it->hdr.nchunks - 1; \
324362
} else { \
325-
BUFFER_HDR_INIT(length, it); \
363+
BUFFER_HDR_INIT(it); \
326364
} \
327365
} \
328366
} while (0)
@@ -460,41 +498,61 @@ static inline int
460498
tfw_hpack_huffman_write(char sym, TfwHttpReq *__restrict req)
461499
{
462500
TfwMsgParseIter *it = &req->pit;
501+
unsigned long to_alloc;
463502
bool np;
464503
int r;
465504

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)
518+
466519
if (it->rspace) {
467520
--it->rspace;
468521
*it->pos++ = sym;
522+
ADJUST_HDR_LEN(it);
469523
return 0;
470524
}
471525

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

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

477534
T_DBG3("%s: it->rspace=%lu, sym=%c, np=%d\n", __func__,
478535
it->rspace, sym, np);
479536

480-
if (!np) {
481-
TfwStr *hdr = &it->hdr;
482-
TfwStr *last = TFW_STR_LAST(hdr);
483-
484-
T_DBG3("%s: add to hdr, hdr->len=%lu, last->len=%lu,"
485-
" last->data=%.*s\n", __func__, hdr->len, last->len,
486-
(int)last->len, last->data);
487-
488-
++hdr->len;
489-
if (!TFW_STR_PLAIN(hdr))
490-
++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);
491546
return 0;
492547
}
493548

494549
r = tfw_hpack_exp_hdr(req->pool, 1, it);
495550
if (unlikely(r))
496551
return r;
497552

553+
*it->pos++ = sym;
554+
it->to_alloc = 0;
555+
498556
return 0;
499557
}
500558

@@ -506,28 +564,14 @@ huffman_decode_tail(TfwHPack *__restrict hp, TfwHttpReq *__restrict req,
506564
unsigned int i;
507565
int r;
508566

509-
#define ADJUST_EXTRA_RSPACE(req) \
510-
do { \
511-
TfwMsgParseIter *it = &req->pit; \
512-
TfwStr *hdr = &it->hdr; \
513-
TfwStr *last = TFW_STR_LAST(hdr); \
514-
\
515-
hdr->len -= it->rspace; \
516-
if (!TFW_STR_PLAIN(hdr)) \
517-
last->len -= it->rspace; \
518-
it->rspace = 0; \
519-
} while (0)
520-
521567
for (;;) {
522568
int shift;
523569

524570
if (hp->curr == -HT_NBITS) {
525-
if (likely(offset == 0)) {
526-
ADJUST_EXTRA_RSPACE(req);
571+
if (likely(offset == 0))
527572
return T_OK;
528-
} else {
573+
else
529574
return T_COMPRESSION;
530-
}
531575
}
532576

533577
i = (hp->hctx << -hp->curr) & HT_NMASK;
@@ -554,10 +598,8 @@ do { \
554598
*/
555599
if (likely(offset == 0)) {
556600
if ((i ^ (HT_EOS_HIGH >> 1)) <
557-
(1U << -hp->curr)) {
558-
ADJUST_EXTRA_RSPACE(req);
601+
(1U << -hp->curr))
559602
return T_OK;
560-
}
561603
}
562604
/*
563605
* The first condition here equivalent to the
@@ -581,10 +623,8 @@ do { \
581623
}
582624
}
583625
if (likely(offset == 0)) {
584-
if ((i ^ (HT_EOS_HIGH >> 1)) < (1U << -hp->curr)) {
585-
ADJUST_EXTRA_RSPACE(req);
626+
if ((i ^ (HT_EOS_HIGH >> 1)) < (1U << -hp->curr))
586627
return T_OK;
587-
}
588628
}
589629
return T_COMPRESSION;
590630

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,14 +67,16 @@ 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
* @nm_len - length of the decoded header's name;
78+
* @to_alloc - count of bytes which, should be allocated, after rspace
79+
* will be exceeded;
7880
* @nm_num - chunks number of the decoded header's name;
7981
* @tag - tag of currently processed decoded header.
8082
* @next - number of chunk which points to the decoded header part
@@ -84,12 +86,13 @@ 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
unsigned long nm_len;
95+
unsigned long to_alloc;
9396
unsigned int nm_num;
9497
unsigned int tag;
9598
unsigned int next;

0 commit comments

Comments
 (0)