diff --git a/Makefile.am b/Makefile.am index b07a65f569..43f17c2b74 100644 --- a/Makefile.am +++ b/Makefile.am @@ -228,6 +228,7 @@ libfreeswitch_la_SOURCES = \ src/switch_odbc.c \ src/g711.c \ src/switch_pcm.c \ + src/switch_profile.c\ libs/stfu/stfu.c \ libs/libteletone/src/libteletone_detect.c \ libs/libteletone/src/libteletone_generate.c \ diff --git a/src/include/private/switch_core_pvt.h b/src/include/private/switch_core_pvt.h index 0a9614f2b4..82631490d2 100644 --- a/src/include/private/switch_core_pvt.h +++ b/src/include/private/switch_core_pvt.h @@ -31,6 +31,9 @@ * this file does not exist!!!! * */ + +#include "switch_profile.h" + #ifndef WIN32 #include #endif @@ -220,6 +223,9 @@ struct switch_runtime { uint32_t runlevel; uint32_t tipping_point; int32_t timer_affinity; + switch_profile_timer_t *profile_timer; + double profile_time; + double min_idle_time; }; extern struct switch_runtime runtime; diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 63f3e4699e..bb2c58daea 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -1901,7 +1901,7 @@ SWITCH_DECLARE(switch_time_t) switch_core_uptime(void); \param val the command arguement (if needed) \return 0 on success nonzero on error */ -SWITCH_DECLARE(int32_t) switch_core_session_ctl(switch_session_ctl_t cmd, int32_t *val); +SWITCH_DECLARE(int32_t) switch_core_session_ctl(switch_session_ctl_t cmd, void *val); /*! \brief Get the output console @@ -1970,6 +1970,8 @@ SWITCH_DECLARE(void) switch_time_set_matrix(switch_bool_t enable); SWITCH_DECLARE(void) switch_time_set_cond_yield(switch_bool_t enable); SWITCH_DECLARE(uint32_t) switch_core_min_dtmf_duration(uint32_t duration); SWITCH_DECLARE(uint32_t) switch_core_max_dtmf_duration(uint32_t duration); +SWITCH_DECLARE(double) switch_core_min_idle_cpu(double new_limit); +SWITCH_DECLARE(double) switch_core_idle_cpu(void); SWITCH_DECLARE(uint32_t) switch_core_default_dtmf_duration(uint32_t duration); SWITCH_DECLARE(switch_status_t) switch_console_set_complete(const char *string); SWITCH_DECLARE(switch_status_t) switch_console_set_alias(const char *string); diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 6616f15ffb..ae0f7be561 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -1458,7 +1458,8 @@ typedef enum { SCSC_SHUTDOWN_NOW, SCSC_CALIBRATE_CLOCK, SCSC_SAVE_HISTORY, - SCSC_CRASH + SCSC_CRASH, + SCSC_MIN_IDLE_CPU } switch_session_ctl_t; typedef enum { diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index 06359cc3b5..8ce821e6a0 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -1439,6 +1439,7 @@ SWITCH_STANDARD_API(status_function) switch_core_session_ctl(SCSC_SPS, &sps); stream->write_function(stream, "%d session(s) %d/%d\n", switch_core_session_count(), last_sps, sps); stream->write_function(stream, "%d session(s) max\n", switch_core_session_limit(0)); + stream->write_function(stream, "min idle cpu %0.2f/%0.2f\n", switch_core_min_idle_cpu(-1.0), switch_core_idle_cpu()); if (html) { stream->write_function(stream, "\n"); @@ -1535,7 +1536,23 @@ SWITCH_STANDARD_API(ctl_function) arg = atoi(argv[1]); } switch_core_session_ctl(SCSC_MAX_SESSIONS, &arg); - stream->write_function(stream, "+OK max sessions: %d\n", arg); + stream->write_function(stream, "+OK max sessions: %f\n", arg); + } else if (!strcasecmp(argv[0], "min_idle_cpu")) { + double d = -1; + + if (argc > 1) { + d = atof(argv[1]); + } + + switch_core_session_ctl(SCSC_MIN_IDLE_CPU, &d); + + if (d) { + stream->write_function(stream, "+OK min idle cpu: %0.2f%\n", d); + } else { + stream->write_function(stream, "+OK min idle cpu: DISABLED\n", d); + } + + } else if (!strcasecmp(argv[0], "max_dtmf_duration")) { if (argc > 1) { arg = atoi(argv[1]); diff --git a/src/switch_core.c b/src/switch_core.c index d08612757e..cbaad6a753 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -82,6 +82,7 @@ static void send_heartbeat(void) switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Session-Count", "%u", switch_core_session_count()); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Session-Per-Sec", "%u", runtime.sps); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Session-Since-Startup", "%" SWITCH_SIZE_T_FMT, switch_core_session_id() - 1); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Idle-CPU", "%f", switch_core_idle_cpu()); switch_event_fire(&event); } } @@ -1442,6 +1443,8 @@ static void switch_load_core_config(const char *file) switch_time_set_matrix(switch_true(var)); } else if (!strcasecmp(var, "max-sessions") && !zstr(val)) { switch_core_session_limit(atoi(val)); + } else if (!strcasecmp(var, "min-idle-cpu") && !zstr(val)) { + switch_core_min_idle_cpu(atof(val)); } else if (!strcasecmp(var, "tipping-point") && !zstr(val)) { runtime.tipping_point = atoi(val); } else if (!strcasecmp(var, "timer-affinity") && !zstr(val)) { @@ -1628,8 +1631,10 @@ SWITCH_DECLARE(uint32_t) switch_core_debug_level(void) } -SWITCH_DECLARE(int32_t) switch_core_session_ctl(switch_session_ctl_t cmd, int32_t *val) +SWITCH_DECLARE(int32_t) switch_core_session_ctl(switch_session_ctl_t cmd, void *val) { + int *intval = (int *) val; + if (switch_test_flag((&runtime), SCF_SHUTTING_DOWN)) { return -1; } @@ -1646,10 +1651,10 @@ SWITCH_DECLARE(int32_t) switch_core_session_ctl(switch_session_ctl_t cmd, int32_ break; case SCSC_SYNC_CLOCK: switch_time_sync(); - *val = 0; + *intval = 0; break; case SCSC_PAUSE_INBOUND: - if (*val) { + if (*intval) { switch_set_flag((&runtime), SCF_NO_NEW_SESSIONS); } else { switch_clear_flag((&runtime), SCF_NO_NEW_SESSIONS); @@ -1700,7 +1705,7 @@ SWITCH_DECLARE(int32_t) switch_core_session_ctl(switch_session_ctl_t cmd, int32_ win_shutdown(); #endif - if (*val) { + if (*intval) { switch_set_flag((&runtime), SCF_RESTART); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Restarting\n"); } else { @@ -1722,7 +1727,7 @@ SWITCH_DECLARE(int32_t) switch_core_session_ctl(switch_session_ctl_t cmd, int32_ win_shutdown(); #endif - if (*val) { + if (*intval) { switch_set_flag((&runtime), SCF_RESTART); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Restarting\n"); } else { @@ -1734,53 +1739,59 @@ SWITCH_DECLARE(int32_t) switch_core_session_ctl(switch_session_ctl_t cmd, int32_ runtime.running = 0; break; case SCSC_CHECK_RUNNING: - *val = runtime.running; + *intval = runtime.running; break; case SCSC_LOGLEVEL: - if (*val > -1) { - runtime.hard_log_level = *val; + if (*intval > -1) { + runtime.hard_log_level = *intval; } if (runtime.hard_log_level > SWITCH_LOG_DEBUG) { runtime.hard_log_level = SWITCH_LOG_DEBUG; } - *val = runtime.hard_log_level; + *intval = runtime.hard_log_level; break; case SCSC_DEBUG_LEVEL: - if (*val > -1) { - if (*val > 10) - *val = 10; - runtime.debug_level = *val; + if (*intval > -1) { + if (*intval > 10) + *intval = 10; + runtime.debug_level = *intval; + } + *intval = runtime.debug_level; + break; + case SCSC_MIN_IDLE_CPU: + { + double *dval = (double *) val; + *dval = switch_core_min_idle_cpu(*dval); } - *val = runtime.debug_level; break; case SCSC_MAX_SESSIONS: - *val = switch_core_session_limit(*val); + *intval = switch_core_session_limit(*intval); break; case SCSC_LAST_SPS: - *val = runtime.sps_last; + *intval = runtime.sps_last; break; case SCSC_MAX_DTMF_DURATION: - *val = switch_core_max_dtmf_duration(*val); + *intval = switch_core_max_dtmf_duration(*intval); break; case SCSC_MIN_DTMF_DURATION: - *val = switch_core_min_dtmf_duration(*val); + *intval = switch_core_min_dtmf_duration(*intval); break; case SCSC_DEFAULT_DTMF_DURATION: - *val = switch_core_default_dtmf_duration(*val); + *intval = switch_core_default_dtmf_duration(*intval); break; case SCSC_SPS: switch_mutex_lock(runtime.throttle_mutex); - if (*val > 0) { - runtime.sps_total = *val; + if (*intval > 0) { + runtime.sps_total = *intval; } - *val = runtime.sps_total; + *intval = runtime.sps_total; switch_mutex_unlock(runtime.throttle_mutex); break; case SCSC_RECLAIM: switch_core_memory_reclaim_all(); - *val = 0; + *intval = 0; break; } diff --git a/src/switch_core_session.c b/src/switch_core_session.c index 5c3c16e381..2cbed02163 100644 --- a/src/switch_core_session.c +++ b/src/switch_core_session.c @@ -1485,6 +1485,10 @@ SWITCH_DECLARE(switch_core_session_t *) switch_core_session_request_uuid(switch_ return NULL; } + if (runtime.min_idle_time > 0 && runtime.profile_time < runtime.min_idle_time) { + return NULL; + } + PROTECT_INTERFACE(endpoint_interface); switch_mutex_lock(runtime.throttle_mutex); @@ -1640,6 +1644,21 @@ SWITCH_DECLARE(uint32_t) switch_core_session_limit(uint32_t new_limit) return session_manager.session_limit; } +SWITCH_DECLARE(double) switch_core_min_idle_cpu(double new_limit) +{ + if (new_limit >= 0) { + runtime.min_idle_time = new_limit; + } + + return runtime.min_idle_time; +} + + +SWITCH_DECLARE(double) switch_core_idle_cpu(void) +{ + return runtime.profile_time; +} + SWITCH_DECLARE(uint32_t) switch_core_sessions_per_second(uint32_t new_limit) { if (new_limit) { diff --git a/src/switch_time.c b/src/switch_time.c index 23e85cbe49..c798ff8227 100644 --- a/src/switch_time.c +++ b/src/switch_time.c @@ -630,6 +630,10 @@ SWITCH_MODULE_RUNTIME_FUNCTION(softtimer_runtime) uint32_t x, tick = 0; switch_time_t ts = 0, last = 0; int fwd_errs = 0, rev_errs = 0; + int profile_tick = 0; + + runtime.profile_timer = switch_new_profile_timer(); + switch_get_system_idle_time(runtime.profile_timer, &runtime.profile_time); #ifdef HAVE_CPU_SET_MACROS if (runtime.timer_affinity > -1) { @@ -741,6 +745,11 @@ SWITCH_MODULE_RUNTIME_FUNCTION(softtimer_runtime) tick += STEP_MS; if (tick >= TICK_PER_SEC) { + if (++profile_tick == 1) { + switch_get_system_idle_time(runtime.profile_timer, &runtime.profile_time); + profile_tick = 0; + } + if (runtime.sps <= 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Over Session Rate of %d!\n", runtime.sps_total); } @@ -803,6 +812,8 @@ SWITCH_MODULE_RUNTIME_FUNCTION(softtimer_runtime) globals.RUNNING = 0; switch_mutex_unlock(globals.mutex); + switch_delete_profile_timer(&runtime.profile_timer); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Soft timer thread exiting.\n"); return SWITCH_STATUS_TERM;