diff --git a/daemon/codec.c b/daemon/codec.c index 9c3a38f4e..8e20384af 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -2960,7 +2960,7 @@ bool codec_parse_payload_type(rtp_payload_type *pt, const str *codec_str) { } rtp_payload_type *codec_make_payload_type(const str *codec_str, enum media_type type) { - __auto_type pt = memory_arena_alloc0(rtp_payload_type); + __auto_type pt = memory_arena_alloc0_lw(rtp_payload_type); if (!codec_parse_payload_type(pt, codec_str)) { payload_type_free(pt); @@ -3033,17 +3033,17 @@ void codec_init_payload_type(rtp_payload_type *pt, enum media_type type) { pt->clock_rate); // allocate strings - pt->encoding = call_str_cpy(&pt->encoding); - pt->encoding_with_params = call_str_cpy_c(full_encoding); - pt->encoding_with_full_params = call_str_cpy_c(full_full_encoding); - pt->encoding_parameters = call_str_cpy_c(params); - pt->format_parameters = call_str_cpy(&pt->format_parameters); - pt->codec_opts = call_str_cpy(&pt->codec_opts); + pt->encoding = memory_arena_str_cpy_lw(&pt->encoding); + pt->encoding_with_params = memory_arena_str_cpy_c_lw(full_encoding); + pt->encoding_with_full_params = memory_arena_str_cpy_c_lw(full_full_encoding); + pt->encoding_parameters = memory_arena_str_cpy_c_lw(params); + pt->format_parameters = memory_arena_str_cpy_lw(&pt->format_parameters); + pt->codec_opts = memory_arena_str_cpy_lw(&pt->codec_opts); // allocate everything from the rtcp-fb list for (__auto_type l = pt->rtcp_fb.head; l; l = l->next) { str *fb = l->data; - l->data = call_str_dup(fb); + l->data = memory_arena_str_dup_lw(fb); } } @@ -5245,12 +5245,19 @@ static rtp_payload_type *codec_add_payload_type(const str *codec, struct call_me void payload_type_clear(rtp_payload_type *p) { - t_queue_clear(&p->rtcp_fb); + t_queue_clear_full(&p->rtcp_fb, memory_arena_str_dup_free_lw); + memory_arena_free_lw(p->encoding.s); + memory_arena_free_lw(p->encoding_with_params.s); + memory_arena_free_lw(p->encoding_with_full_params.s); + memory_arena_free_lw(p->encoding_parameters.s); + memory_arena_free_lw(p->format_parameters.s); + memory_arena_free_lw(p->codec_opts.s); ZERO(*p); p->payload_type = -1; } void payload_type_free(rtp_payload_type *p) { payload_type_clear(p); + memory_arena_free_lw(p); } void payload_type_destroy(rtp_payload_type **p) { if (*p) @@ -5274,7 +5281,7 @@ static void rtp_payload_type_copy(rtp_payload_type *dst, const rtp_payload_type } rtp_payload_type *rtp_payload_type_dup(const rtp_payload_type *pt) { - __auto_type pt_copy = memory_arena_alloc0(rtp_payload_type); + __auto_type pt_copy = memory_arena_alloc0_lw(rtp_payload_type); rtp_payload_type_copy(pt_copy, pt); return pt_copy; } @@ -5327,8 +5334,10 @@ static int __codec_options_set1(call_t *call, rtp_payload_type *pt, const str *e // match - apply options if (pt_parsed->bitrate) pt->bitrate = pt_parsed->bitrate; - if (!pt->codec_opts.len && pt_parsed->codec_opts.len) - pt->codec_opts = pt_parsed->codec_opts; + if (!pt->codec_opts.len && pt_parsed->codec_opts.len) { + memory_arena_free_lw(pt->codec_opts.s); + pt->codec_opts = memory_arena_str_cpy_lw(&pt_parsed->codec_opts); + } payload_type_free(pt_parsed); return 1; } @@ -5839,7 +5848,7 @@ void __codec_store_populate(struct codec_store *dst, struct codec_store *src, st pt->for_transcoding = orig_pt->for_transcoding; pt->accepted = orig_pt->accepted; pt->bitrate = orig_pt->bitrate; - pt->codec_opts = orig_pt->codec_opts; + pt->codec_opts = memory_arena_str_cpy_lw(&orig_pt->codec_opts); if (pt->for_transcoding) codec_touched(dst, pt); } diff --git a/daemon/main.c b/daemon/main.c index 0cd8cab63..1bdb1a70f 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -843,6 +843,7 @@ static void options(int *argc, char ***argv, charp_ht templates) { #endif { "log-format", 0, 0, G_OPTION_ARG_STRING, &log_format, "Log prefix format", "default|parsable"}, { "xmlrpc-format",'x', 0, G_OPTION_ARG_INT, &rtpe_config.fmt, "XMLRPC timeout request format to use. 0: SEMS DI, 1: call-id only, 2: Kamailio", "INT" }, + { "lightweight",0,0, G_OPTION_ARG_NONE, &rtpe_config.lightweight, "Decrease use of memory arenas", NULL }, { "num-threads", 0, 0, G_OPTION_ARG_INT, &rtpe_config.num_threads, "Number of worker threads to create", "INT" }, { "media-num-threads", 0, 0, G_OPTION_ARG_INT, &rtpe_config.media_num_threads, "Number of worker threads for media playback", "INT" }, { "kernel-num-threads", 0, 0, G_OPTION_ARG_INT, &rtpe_config.kernel_num_threads,"Number of worker threads for kernel RTP", "INT" }, @@ -1851,6 +1852,9 @@ static void init_everything(charp_ht templates) { static void create_everything(void) { rtpe_now = now_us(); + if (rtpe_config.lightweight || getenv("RTPENGINE_LIGHTWEIGHT")) + memory_arena_set_leightweight(); + // either one global poller, or one per thread for media sockets plus one for control sockets #ifdef HAVE_LIBURING if (rtpe_config.common.io_uring) { diff --git a/daemon/media_player.c b/daemon/media_player.c index c0d770cf9..6f2fd7134 100644 --- a/daemon/media_player.c +++ b/daemon/media_player.c @@ -922,7 +922,11 @@ static bool media_player_cache_entry_init(struct media_player *mp, const rtp_pay // steal coder data entry->coder = mp->coder; + + rtp_payload_type src_pt_cpy = mp->coder.handler->source_pt; + rtp_payload_type dst_pt_cpy = mp->coder.handler->dest_pt; ZERO(mp->coder); + mp->coder.duration = entry->coder.duration; // retain this for reporting if (entry->coder.avioctx) entry->coder.avioctx->opaque = &entry->coder; // format context pointer must point to new coder @@ -936,6 +940,9 @@ static bool media_player_cache_entry_init(struct media_player *mp, const rtp_pay codec_init_payload_type(&entry->coder.handler->dest_pt, MT_UNKNOWN); call_memory_arena_set(mp->call); + payload_type_clear(&src_pt_cpy); + payload_type_clear(&dst_pt_cpy); + // use low priority (10 nice) thread_create_detach_prio(media_player_cache_entry_decoder_thread, obj_get(entry), NULL, 10, "mp decoder"); diff --git a/daemon/memory_arena.c b/daemon/memory_arena.c index eaea35137..90bb73b42 100644 --- a/daemon/memory_arena.c +++ b/daemon/memory_arena.c @@ -11,3 +11,16 @@ void memory_arena_free(void *p) { size_t *s = p; // first element is the size munmap(p, *s); } + + +static void dummy_free(void *p) { } + +void *(*__memory_arena_alloc_lw)(size_t len) = __memory_arena_alloc; +void *(*__memory_arena_alloc0_lw)(size_t len) = __memory_arena_alloc0; +void (*memory_arena_free_lw)(void *) = dummy_free; + +void memory_arena_set_leightweight(void) { + __memory_arena_alloc_lw = g_malloc; + __memory_arena_alloc0_lw = g_malloc0; + memory_arena_free_lw = g_free; +} diff --git a/daemon/sdp.c b/daemon/sdp.c index 23552c65e..362f347b4 100644 --- a/daemon/sdp.c +++ b/daemon/sdp.c @@ -1659,7 +1659,7 @@ static bool __rtp_payload_types(struct stream_params *sp, struct sdp_media *medi ptrfc = rtp_get_rfc_payload_type(i); ptl = g_hash_table_lookup(ht_rtpmap, GINT_TO_POINTER(i)); - pt = memory_arena_alloc0(rtp_payload_type); + pt = memory_arena_alloc0_lw(rtp_payload_type); if (ptl) *pt = *ptl; else if (ptrfc) diff --git a/docs/rtpengine.md b/docs/rtpengine.md index aeac15665..f8ee0180f 100644 --- a/docs/rtpengine.md +++ b/docs/rtpengine.md @@ -447,6 +447,16 @@ call to inject-DTMF won't be sent to __\-\-dtmf-log-dest=__ or __\-\-listen-tcp- Suffix to be added to particular data fields in log files that are deemed sensitive and/or private information. Defaults to an empty string. +- __\-\-lightweight__ + + Decrease use of memory arenas. This is mostly beneficial for use cases + involving long-running calls which see a lot of session updates, and + results in a smaller memory footprint, at the expense of higher CPU usage + due to heavier use of the system's memory allocator. + + This mode can also be enabled by setting the environment variable + `RTPENGINE_LIGHTWEIGHT` to any value. + - __\-\-num-threads=__*INT* How many worker threads to create, must be at least one. diff --git a/include/call.h b/include/call.h index 1837cd721..9246d7ebf 100644 --- a/include/call.h +++ b/include/call.h @@ -1023,7 +1023,6 @@ G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(call_q, call_q_unlock_release); #include "rtp.h" #define call_malloc memory_arena_alloc -#define call_dup memory_arena_dup #define call_strdup memory_arena_strdup #define call_strdup_str memory_arena_strdup_str diff --git a/include/main.h b/include/main.h index 75513a506..35bd34838 100644 --- a/include/main.h +++ b/include/main.h @@ -141,6 +141,7 @@ enum endpoint_learning { X(amr_cn_dtx) \ X(evs_cn_dtx) \ X(moh_prevent_double_hold) \ + X(lightweight) \ #define RTPE_CONFIG_CHARP_PARAMS \ X(b2b_url) \ diff --git a/include/memory_arena.h b/include/memory_arena.h index 0d7a2be69..03f46ee73 100644 --- a/include/memory_arena.h +++ b/include/memory_arena.h @@ -16,12 +16,15 @@ INLINE void *__memory_arena_alloc(size_t len) { ret = arena_alloc(memory_arena, len); return ret; } + #define memory_arena_alloc(type) ((type *) __memory_arena_alloc(sizeof(type))) + INLINE void *__memory_arena_alloc0(size_t len) { void *ret = __memory_arena_alloc(len); memset(ret, 0, len); return ret; } + #define memory_arena_alloc0(type) ((type *) __memory_arena_alloc0(sizeof(type))) INLINE char *__memory_arena_memdup(const void *b, size_t len) { @@ -81,4 +84,56 @@ INLINE str *memory_arena_str_dup(const str *in) { return out; } + +extern void *(*__memory_arena_alloc_lw)(size_t len); +extern void *(*__memory_arena_alloc0_lw)(size_t len); +extern void (*memory_arena_free_lw)(void *); + +#define memory_arena_alloc0_lw(type) ((type *) __memory_arena_alloc0_lw(sizeof(type))) +#define memory_arena_alloc_lw(type) ((type *) __memory_arena_alloc_lw(sizeof(type))) + +INLINE char *memory_arena_dup_lw(const char *b, size_t len) { + char *ret = __memory_arena_alloc_lw(len + 1); + memcpy(ret, b, len); + ret[len] = '\0'; + return ret; +} +INLINE char *memory_arena_strdup_len_lw(const char *s, size_t len) { + if (!s) + return NULL; + return memory_arena_dup_lw(s, len); +} +INLINE str memory_arena_str_cpy_fn_lw(const char *in, size_t len) { + str out; + if (!in) { + out = STR_NULL; + return out; + } + out.s = memory_arena_strdup_len_lw(in, len); + out.len = len; + out.arena = NULL; + return out; +} +INLINE str memory_arena_str_cpy_lw(const str *in) { + return memory_arena_str_cpy_fn_lw((in ? in->s : NULL), (in ? in->len : 0)); +} +INLINE str memory_arena_str_cpy_len_lw(const char *in, size_t len) { + return memory_arena_str_cpy_fn_lw(in, len); +} +INLINE str memory_arena_str_cpy_c_lw(const char *in) { + return memory_arena_str_cpy_len_lw(in, in ? strlen(in) : 0); +} +INLINE str *memory_arena_str_dup_lw(const str *in) { + __auto_type out = memory_arena_alloc_lw(str); + *out = memory_arena_str_cpy_fn_lw(in->s, in->len); + return out; +} + +INLINE void memory_arena_str_dup_free_lw(str *s) { + memory_arena_free_lw(s->s); + memory_arena_free_lw(s); +} + +void memory_arena_set_leightweight(void); + #endif