From 8a0e9ccf1f939e75bc425e8b80d087a77499e69a Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 14 Sep 2006 00:15:03 +0000 Subject: [PATCH] performance tweaks git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@2693 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- conf/freeswitch.xml | 1 + .../endpoints/mod_dingaling/mod_dingaling.c | 4 + src/mod/endpoints/mod_sofia/mod_sofia.c | 9 +- .../timers/mod_threadtimer/mod_threadtimer.c | 275 ++++++++++++++++++ .../mod_threadtimer/mod_threadtimer.vcproj | 210 +++++++++++++ src/switch_buffer.c | 18 +- src/switch_core.c | 7 +- src/switch_ivr.c | 15 +- src/switch_rtp.c | 32 +- 9 files changed, 541 insertions(+), 30 deletions(-) create mode 100644 src/mod/timers/mod_threadtimer/mod_threadtimer.c create mode 100644 src/mod/timers/mod_threadtimer/mod_threadtimer.vcproj diff --git a/conf/freeswitch.xml b/conf/freeswitch.xml index e3b365da5e..4f5afba2a2 100644 --- a/conf/freeswitch.xml +++ b/conf/freeswitch.xml @@ -112,6 +112,7 @@ + diff --git a/src/mod/endpoints/mod_dingaling/mod_dingaling.c b/src/mod/endpoints/mod_dingaling/mod_dingaling.c index 0105c83636..385b9222c0 100644 --- a/src/mod/endpoints/mod_dingaling/mod_dingaling.c +++ b/src/mod/endpoints/mod_dingaling/mod_dingaling.c @@ -1242,6 +1242,10 @@ static switch_status_t init_profile(struct mdl_profile *profile, uint8_t login) profile->exten) { ldl_handle_t *handle; + if (switch_test_flag(profile, TFLAG_TIMER) && !profile->timer_name) { + profile->timer_name = switch_core_strdup(module_pool, "soft"); + } + if (login) { if (ldl_handle_init(&handle, profile->login, diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index b045a8df3a..4653f87d3f 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -642,7 +642,6 @@ static switch_status_t sofia_on_transmit(switch_core_session_t *session) static void deactivate_rtp(private_object_t *tech_pvt) { int loops = 0;//, sock = -1; - if (switch_rtp_ready(tech_pvt->rtp_session)) { while (loops < 10 && (switch_test_flag(tech_pvt, TFLAG_READING) || switch_test_flag(tech_pvt, TFLAG_WRITING))) { switch_yield(10000); @@ -730,10 +729,6 @@ static switch_status_t activate_rtp(private_object_t *tech_pvt) ms = tech_pvt->read_codec.implementation->microseconds_per_frame; flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_RAW_WRITE | SWITCH_RTP_FLAG_MINI); - if (switch_test_flag(tech_pvt, TFLAG_TIMER)) { - flags = (switch_rtp_flag_t) (flags | SWITCH_RTP_FLAG_USE_TIMER); - } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "RTP [%s] %s:%d->%s:%d codec: %u ms: %d\n", switch_channel_get_name(channel), @@ -1846,6 +1841,10 @@ static switch_status_t config_sofia(int reload) } } + if (switch_test_flag(profile, TFLAG_TIMER) && !profile->timer_name) { + profile->timer_name = switch_core_strdup(profile->pool, "soft"); + } + if (!profile->username) { profile->username = switch_core_strdup(profile->pool, "FreeSWITCH"); } diff --git a/src/mod/timers/mod_threadtimer/mod_threadtimer.c b/src/mod/timers/mod_threadtimer/mod_threadtimer.c new file mode 100644 index 0000000000..8de6c371f6 --- /dev/null +++ b/src/mod/timers/mod_threadtimer/mod_threadtimer.c @@ -0,0 +1,275 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005/2006, Anthony Minessale II + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Anthony Minessale II + * + * + * mod_threadtimer.c -- Software Timer Module + * + */ +#include +#include + +static switch_memory_pool_t *module_pool = NULL; + +static struct { + int32_t RUNNING; + switch_mutex_t *mutex; +} globals; + +static const char modname[] = "mod_threadtimer"; +#define MAX_ELEMENTS 1000 + +struct timer_private { + uint32_t tick; + uint32_t reference; + uint32_t interval; + switch_mutex_t *mutex; + struct timer_private *next; +}; + +typedef struct timer_private timer_private_t; + +struct timer_head { + timer_private_t *private_info; + switch_mutex_t *mutex; +}; +typedef struct timer_head timer_head_t; + +static timer_head_t *TIMER_MATRIX[MAX_ELEMENTS+1]; + +static inline switch_status_t timer_init(switch_timer_t *timer) +{ + timer_private_t *private_info; + timer_head_t *head; + + if ((private_info = switch_core_alloc(timer->memory_pool, sizeof(*private_info)))) { + timer->private_info = private_info; + if (!TIMER_MATRIX[timer->interval]) { + if (!(TIMER_MATRIX[timer->interval] = switch_core_alloc(module_pool, sizeof(timer_head_t)))) { + return SWITCH_STATUS_MEMERR; + } + switch_mutex_init(&TIMER_MATRIX[timer->interval]->mutex, SWITCH_MUTEX_NESTED, module_pool); + } + + head = TIMER_MATRIX[timer->interval]; + + switch_mutex_init(&private_info->mutex, SWITCH_MUTEX_NESTED, timer->memory_pool); + private_info->interval = timer->interval; + + switch_mutex_lock(head->mutex); + private_info->next = head->private_info; + head->private_info = private_info; + switch_mutex_unlock(head->mutex); + + return SWITCH_STATUS_SUCCESS; + } + + return SWITCH_STATUS_MEMERR; +} + +#define MAX_TICKS 0xFFFFFF00 +#define check_overflow(p) if (p->reference > MAX_TICKS) {\ + switch_mutex_lock(p->mutex);\ + p->reference = p->tick = 0;\ + switch_mutex_unlock(p->mutex);\ + }\ + + +static inline switch_status_t timer_step(switch_timer_t *timer) +{ + timer_private_t *private_info = timer->private_info; + + switch_mutex_lock(private_info->mutex); + private_info->reference += private_info->interval; + switch_mutex_unlock(private_info->mutex); + + return SWITCH_STATUS_SUCCESS; +} + + +static inline switch_status_t timer_next(switch_timer_t *timer) +{ + timer_private_t *private_info = timer->private_info; + + + timer_step(timer); + while (private_info->tick < private_info->reference) { + switch_yield(1000); + } + check_overflow(private_info); + timer->samplecount += timer->samples; + + return SWITCH_STATUS_SUCCESS; +} + +static inline switch_status_t timer_check(switch_timer_t *timer) + +{ + timer_private_t *private_info = timer->private_info; + switch_status_t status; + + switch_mutex_lock(private_info->mutex); + if (private_info->tick < private_info->reference) { + status = SWITCH_STATUS_FALSE; + } else { + private_info->reference += private_info->interval; + check_overflow(private_info); + status = SWITCH_STATUS_SUCCESS; + } + switch_mutex_unlock(private_info->mutex); + + return status; +} + + +static inline switch_status_t timer_destroy(switch_timer_t *timer) +{ + timer_private_t *private_info = timer->private_info; + timer_head_t *head; + timer_private_t *ptr, *last = NULL; + + head = TIMER_MATRIX[timer->interval]; + assert(head != NULL); + assert(private_info != NULL); + + switch_mutex_lock(head->mutex); + for(ptr = head->private_info; ptr; ptr = ptr->next) { + if (ptr == private_info) { + if (last) { + last->next = private_info->next; + } else { + head->private_info = private_info->next; + } + } + last = ptr; + } + switch_mutex_unlock(head->mutex); + + timer->private_info = NULL; + return SWITCH_STATUS_SUCCESS; +} + +static const switch_timer_interface_t timer_interface = { + /*.interface_name */ "thread_soft", + /*.timer_init */ timer_init, + /*.timer_next */ timer_next, + /*.timer_step */ timer_step, + /*.timer_check */ timer_check, + /*.timer_destroy */ timer_destroy +}; + +static const switch_loadable_module_interface_t mod_threadtimer_module_interface = { + /*.module_name */ modname, + /*.endpoint_interface */ NULL, + /*.timer_interface */ &timer_interface, + /*.switch_dialplan_interface */ NULL, + /*.switch_codec_interface */ NULL, + /*.switch_application_interface */ NULL +}; + +SWITCH_MOD_DECLARE(switch_status_t) switch_module_load(const switch_loadable_module_interface_t **module_interface, char *filename) +{ + + if (switch_core_new_memory_pool(&module_pool) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "OH OH no pool\n"); + return SWITCH_STATUS_MEMERR; + } + + /* connect my internal structure to the blank pointer passed to me */ + *module_interface = &mod_threadtimer_module_interface; + + /* indicate that the module should continue to be loaded */ + return SWITCH_STATUS_SUCCESS; +} + +SWITCH_MOD_DECLARE(switch_status_t) switch_module_runtime(void) +{ + switch_time_t reference = switch_time_now(); + uint32_t current_ms = 0; + timer_private_t *ptr; + uint32_t x; + + memset(&globals, 0, sizeof(globals)); + switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, module_pool); + + globals.RUNNING = 1; + + while(globals.RUNNING == 1) { + reference += 1000; + + while (switch_time_now() < reference) { + switch_yield(500); + } + + current_ms++; + + for (x = 0; x < 1000; x++) { + int i = x, index; + if (i == 0) { + i = 1; + } + + index = (current_ms % i == 0) ? i : 0; + + if (TIMER_MATRIX[index] && TIMER_MATRIX[index]->private_info) { + switch_mutex_lock(TIMER_MATRIX[index]->mutex); + for (ptr = TIMER_MATRIX[index]->private_info; ptr; ptr = ptr->next) { + switch_mutex_lock(ptr->mutex); + ptr->tick += ptr->interval; + switch_mutex_unlock(ptr->mutex); + } + switch_mutex_unlock(TIMER_MATRIX[index]->mutex); + } + } + + if (current_ms == MAX_ELEMENTS) { + current_ms = 0; + } + } + + switch_mutex_lock(globals.mutex); + globals.RUNNING = 0; + switch_mutex_unlock(globals.mutex); + + return SWITCH_STATUS_TERM; +} + + +SWITCH_MOD_DECLARE(switch_status_t) switch_module_shutdown(void) +{ + + if (globals.RUNNING) { + switch_mutex_lock(globals.mutex); + globals.RUNNING = -1; + switch_mutex_unlock(globals.mutex); + + while (globals.RUNNING) { + switch_yield(10000); + } + } + + return SWITCH_STATUS_SUCCESS; +} diff --git a/src/mod/timers/mod_threadtimer/mod_threadtimer.vcproj b/src/mod/timers/mod_threadtimer/mod_threadtimer.vcproj new file mode 100644 index 0000000000..fe6ced3ad1 --- /dev/null +++ b/src/mod/timers/mod_threadtimer/mod_threadtimer.vcproj @@ -0,0 +1,210 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/switch_buffer.c b/src/switch_buffer.c index 1245378778..b31ae6c76f 100644 --- a/src/switch_buffer.c +++ b/src/switch_buffer.c @@ -39,7 +39,8 @@ typedef enum { } switch_buffer_flag_t; struct switch_buffer { - unsigned char *data; + switch_byte_t *data; + switch_byte_t *front; switch_size_t used; switch_size_t datalen; switch_size_t max_len; @@ -56,6 +57,7 @@ SWITCH_DECLARE(switch_status_t) switch_buffer_create(switch_memory_pool_t *pool, && (new_buffer->data = switch_core_alloc(pool, max_len)) != 0) { new_buffer->datalen = max_len; new_buffer->id = buffer_id++; + new_buffer->front = new_buffer->data; *buffer = new_buffer; return SWITCH_STATUS_SUCCESS; } @@ -84,6 +86,7 @@ SWITCH_DECLARE(switch_status_t) switch_buffer_create_dynamic(switch_buffer_t **b new_buffer->datalen = start_len; new_buffer->id = buffer_id++; new_buffer->blocksize = blocksize; + new_buffer->front = new_buffer->data; switch_set_flag(new_buffer, SWITCH_BUFFER_FLAG_DYNAMIC); *buffer = new_buffer; @@ -163,8 +166,9 @@ SWITCH_DECLARE(switch_size_t) switch_buffer_read(switch_buffer_t *buffer, void * reading = buffer->used; } - memcpy(data, buffer->data, reading); - memmove(buffer->data, buffer->data + reading, buffer->datalen - reading); + memcpy(data, buffer->front, reading); + + buffer->front += reading; buffer->used -= reading; //if (buffer->id == 3) printf("%u o %d = %d\n", buffer->id, (uint32_t)reading, (uint32_t)buffer->used); return reading; @@ -180,10 +184,15 @@ SWITCH_DECLARE(switch_size_t) switch_buffer_write(switch_buffer_t *buffer, void freespace = buffer->datalen - buffer->used; + if (buffer->front != buffer->data) { + memmove(buffer->data, buffer->front, buffer->used); + buffer->front = buffer->data; + } + if (switch_test_flag(buffer, SWITCH_BUFFER_FLAG_DYNAMIC)) { if (freespace < datalen) { switch_size_t new_size, new_block_size; - + new_size = buffer->datalen + datalen; new_block_size = buffer->datalen + buffer->blocksize; @@ -194,7 +203,6 @@ SWITCH_DECLARE(switch_size_t) switch_buffer_write(switch_buffer_t *buffer, void if (!(buffer->data = realloc(buffer->data, new_size))) { return 0; } - buffer->datalen = new_size; } } diff --git a/src/switch_core.c b/src/switch_core.c index 8e7ba0ff92..a5d4f0a7d5 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -39,6 +39,7 @@ #endif //#define DEBUG_ALLOC +#define DO_EVENTS #ifdef CRASH_PROT #define __CP "ENABLED" @@ -3268,7 +3269,7 @@ static void switch_core_sql_thread_launch(void) } - +#ifdef DO_EVENTS static void core_event_handler(switch_event_t *event) { char *sql = NULL; @@ -3371,6 +3372,7 @@ static void core_event_handler(switch_event_t *event) sql = NULL; } } +#endif SWITCH_DECLARE(void) switch_core_set_globals(void) { @@ -3553,11 +3555,12 @@ SWITCH_DECLARE(switch_status_t) switch_core_init(char *console, const char **err switch_core_db_exec(runtime.db, create_channels_sql, NULL, NULL, NULL); switch_core_db_exec(runtime.db, create_calls_sql, NULL, NULL, NULL); switch_core_db_exec(runtime.db, create_interfaces_sql, NULL, NULL, NULL); - +#ifdef DO_EVENTS if (switch_event_bind("core_db", SWITCH_EVENT_ALL, SWITCH_EVENT_SUBCLASS_ANY, core_event_handler, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind event handler!\n"); } +#endif } runtime.session_id = 1; diff --git a/src/switch_ivr.c b/src/switch_ivr.c index bbebb11603..6228190a50 100644 --- a/src/switch_ivr.c +++ b/src/switch_ivr.c @@ -580,6 +580,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session(switch_core_session_t return SWITCH_STATUS_SUCCESS; } +#define FILE_STARTSAMPLES 512 * 128 +#define FILE_BLOCKSIZE 1024 SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *session, switch_file_handle_t *fh, char *file, @@ -589,7 +591,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess unsigned int buflen) { switch_channel_t *channel; - short abuf[960]; + int16_t abuf[FILE_STARTSAMPLES+1]; char dtmf[128]; uint32_t interval = 0, samples = 0; uint32_t ilen = 0; @@ -676,6 +678,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess assert(read_codec != NULL); interval = read_codec->implementation->microseconds_per_frame / 1000; + if (!fh->audio_buffer) { + switch_buffer_create_dynamic(&fh->audio_buffer, FILE_BLOCKSIZE, (FILE_STARTSAMPLES * sizeof(int16_t)) + FILE_BLOCKSIZE, 0); + } codec_name = "L16"; @@ -771,8 +776,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess olen = ilen; do_speed = 0; } else { - olen = ilen; + olen = FILE_STARTSAMPLES; switch_core_file_read(fh, abuf, &olen); + switch_buffer_write(fh->audio_buffer, abuf, olen * 2); + olen = switch_buffer_read(fh->audio_buffer, abuf, ilen * 2) / 2; } if (done || olen <= 0) { @@ -796,9 +803,6 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess short *bp = write_frame.data; switch_size_t wrote = 0; - if (!fh->audio_buffer) { - switch_buffer_create(fh->memory_pool, &fh->audio_buffer, SWITCH_RECCOMMENDED_BUFFER_SIZE); - } supplement = (int) (factor * olen); newlen = (fh->speed > 0) ? olen - supplement : olen + supplement; @@ -872,6 +876,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "done playing file\n"); switch_core_file_close(fh); + switch_buffer_destroy(&fh->audio_buffer); switch_core_codec_destroy(&codec); if (timer_name) { diff --git a/src/switch_rtp.c b/src/switch_rtp.c index 3927290037..6ae324e0ca 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -171,6 +171,8 @@ struct switch_rtp { switch_payload_t te; switch_mutex_t *flag_mutex; switch_timer_t timer; + uint8_t ready; + switch_time_t last_time; }; static int global_init = 0; @@ -472,13 +474,15 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session return SWITCH_STATUS_FALSE; } } - - if (!timer_name) { - timer_name = "soft"; + switch_clear_flag_locked(rtp_session, SWITCH_RTP_FLAG_USE_TIMER); + if (timer_name) { + if (switch_core_timer_init(&rtp_session->timer, timer_name, ms_per_packet / 1000, packet_size, rtp_session->pool) != SWITCH_STATUS_SUCCESS) { + return SWITCH_STATUS_FALSE; + } + switch_set_flag_locked(rtp_session, SWITCH_RTP_FLAG_USE_TIMER); } - switch_core_timer_init(&rtp_session->timer, timer_name, ms_per_packet / 1000, packet_size, rtp_session->pool); - + rtp_session->ready++; *new_rtp_session = rtp_session; return SWITCH_STATUS_SUCCESS; @@ -556,13 +560,12 @@ SWITCH_DECLARE(void) switch_rtp_kill_socket(switch_rtp_t *rtp_session) SWITCH_DECLARE(uint8_t) switch_rtp_ready(switch_rtp_t *rtp_session) { - return (rtp_session != NULL && switch_test_flag(rtp_session, SWITCH_RTP_FLAG_IO)) ? 1 : 0; + return (rtp_session != NULL && rtp_session->ready) ? 1 : 0; } SWITCH_DECLARE(void) switch_rtp_destroy(switch_rtp_t **rtp_session) { - - if (!switch_test_flag((*rtp_session), SWITCH_RTP_FLAG_IO)) { + if (!switch_rtp_ready(*rtp_session)) { return; } @@ -721,13 +724,13 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ { switch_size_t bytes; switch_status_t status; - - + switch_time_t now = 0; + for(;;) { bytes = sizeof(rtp_msg_t); status = switch_socket_recvfrom(rtp_session->from_addr, rtp_session->sock, 0, (void *)&rtp_session->recv_msg, &bytes); - if (!SWITCH_STATUS_IS_BREAK(status)) { + if (!SWITCH_STATUS_IS_BREAK(status) && rtp_session->timer.timer_interface) { switch_core_timer_step(&rtp_session->timer); } @@ -789,9 +792,12 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ } } } - if (switch_core_timer_check(&rtp_session->timer) == SWITCH_STATUS_SUCCESS) { + + if ((!rtp_session->timer.timer_interface && (now=switch_time_now()) - rtp_session->last_time > 10000) || + switch_core_timer_check(&rtp_session->timer) == SWITCH_STATUS_SUCCESS) { do_2833(rtp_session); - + rtp_session->last_time = now; + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_USE_TIMER)) { /* We're late! We're Late!*/ if (!switch_test_flag(rtp_session, SWITCH_RTP_FLAG_NOBLOCK) && status == SWITCH_STATUS_BREAK) {