mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-22 14:21:25 +02:00
When building with DEBUG_MEM_STATS, we only see b_alloc() and b_free() as users of the "buffer" pool, because all call places rely on these more convenient functions. It's annoying because it makes it very hard to see which parts of the code are consuming buffers. By switching the b_alloc() and b_free() inline functions to macros, we can now finally track the users of struct buffer, e.g: mux_h1.c:513 P_FREE size: 1275002880 calls: 38910 size/call: 32768 buffer mux_h1.c:498 P_ALLOC size: 1912438784 calls: 58363 size/call: 32768 buffer stream.c:763 P_FREE size: 4121493504 calls: 125778 size/call: 32768 buffer stream.c:759 P_FREE size: 2061697024 calls: 62918 size/call: 32768 buffer stream.c:742 P_ALLOC size: 3341123584 calls: 101963 size/call: 32768 buffer stream.c:632 P_FREE size: 1275068416 calls: 38912 size/call: 32768 buffer stream.c:631 P_FREE size: 637435904 calls: 19453 size/call: 32768 buffer channel.h:850 P_ALLOC size: 4116480000 calls: 125625 size/call: 32768 buffer channel.h:850 P_ALLOC size: 720896 calls: 22 size/call: 32768 buffer dynbuf.c:55 P_FREE size: 65536 calls: 2 size/call: 32768 buffer Let's do this since it doesn't change anything for the output code (beyond adding the call places). Interestingly the code even got slightly smaller now.
129 lines
3.8 KiB
C
129 lines
3.8 KiB
C
/*
|
|
* include/haproxy/dynbuf.h
|
|
* Buffer management functions.
|
|
*
|
|
* Copyright (C) 2000-2020 Willy Tarreau - w@1wt.eu
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation, version 2.1
|
|
* exclusively.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#ifndef _HAPROXY_DYNBUF_H
|
|
#define _HAPROXY_DYNBUF_H
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <import/ist.h>
|
|
#include <haproxy/activity.h>
|
|
#include <haproxy/api.h>
|
|
#include <haproxy/buf.h>
|
|
#include <haproxy/chunk.h>
|
|
#include <haproxy/dynbuf-t.h>
|
|
#include <haproxy/pool.h>
|
|
|
|
extern struct pool_head *pool_head_buffer;
|
|
|
|
int init_buffer(void);
|
|
void buffer_dump(FILE *o, struct buffer *b, int from, int to);
|
|
|
|
/*****************************************************************/
|
|
/* These functions are used to compute various buffer area sizes */
|
|
/*****************************************************************/
|
|
|
|
/* Return 1 if the buffer has less than 1/4 of its capacity free, otherwise 0 */
|
|
static inline int buffer_almost_full(const struct buffer *buf)
|
|
{
|
|
if (b_is_null(buf))
|
|
return 0;
|
|
|
|
return b_almost_full(buf);
|
|
}
|
|
|
|
/**************************************************/
|
|
/* Functions below are used for buffer allocation */
|
|
/**************************************************/
|
|
|
|
/* Ensures that <buf> is allocated, or allocates it. If no memory is available,
|
|
* ((char *)1) is assigned instead with a zero size. The allocated buffer is
|
|
* returned, or NULL in case no memory is available.
|
|
*/
|
|
#define b_alloc(_buf) \
|
|
({ \
|
|
char *_area; \
|
|
struct buffer *_retbuf = _buf; \
|
|
\
|
|
if (!_retbuf->size) { \
|
|
*_retbuf = BUF_WANTED; \
|
|
_area = pool_alloc_flag(pool_head_buffer, POOL_F_NO_POISON); \
|
|
if (unlikely(!_area)) { \
|
|
activity[tid].buf_wait++; \
|
|
_retbuf = NULL; \
|
|
} \
|
|
else { \
|
|
_retbuf->area = _area; \
|
|
_retbuf->size = pool_head_buffer->size; \
|
|
} \
|
|
} \
|
|
_retbuf; \
|
|
})
|
|
|
|
/* Releases buffer <buf> (no check of emptiness). The buffer's head is marked
|
|
* empty.
|
|
*/
|
|
#define __b_free(_buf) \
|
|
do { \
|
|
char *area = (_buf)->area; \
|
|
\
|
|
/* let's first clear the area to save an occasional "show sess all" \
|
|
* glancing over our shoulder from getting a dangling pointer. \
|
|
*/ \
|
|
*(_buf) = BUF_NULL; \
|
|
__ha_barrier_store(); \
|
|
pool_free(pool_head_buffer, area); \
|
|
} while (0) \
|
|
|
|
/* Releases buffer <buf> if allocated, and marks it empty. */
|
|
#define b_free(_buf) \
|
|
do { \
|
|
if ((_buf)->size) \
|
|
__b_free((_buf)); \
|
|
} while (0)
|
|
|
|
/* Offer one or multiple buffer currently belonging to target <from> to whoever
|
|
* needs one. Any pointer is valid for <from>, including NULL. Its purpose is
|
|
* to avoid passing a buffer to oneself in case of failed allocations (e.g.
|
|
* need two buffers, get one, fail, release it and wake up self again). In case
|
|
* of normal buffer release where it is expected that the caller is not waiting
|
|
* for a buffer, NULL is fine. It will wake waiters on the current thread only.
|
|
*/
|
|
void __offer_buffers(void *from, unsigned int count);
|
|
|
|
static inline void offer_buffers(void *from, unsigned int count)
|
|
{
|
|
if (!LIST_ISEMPTY(&th_ctx->buffer_wq))
|
|
__offer_buffers(from, count);
|
|
}
|
|
|
|
|
|
#endif /* _HAPROXY_DYNBUF_H */
|
|
|
|
/*
|
|
* Local variables:
|
|
* c-indent-level: 8
|
|
* c-basic-offset: 8
|
|
* End:
|
|
*/
|