Addition of new tuning parameters for epoll spins and wait time
This commit is contained in:
@ -1106,6 +1106,31 @@ config_threadcount()
|
||||
return gateway.n_threads;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of non-blocking polls to be done before a blocking poll
|
||||
* is issued.
|
||||
*
|
||||
* @return The number of blocking poll calls to make before a blocking call
|
||||
*/
|
||||
unsigned int
|
||||
config_nbpolls()
|
||||
{
|
||||
return gateway.n_nbpoll;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the configured number of milliseconds for which we wait when we do
|
||||
* a blocking poll call.
|
||||
*
|
||||
* @return The number of milliseconds to sleep in a blocking poll call
|
||||
*/
|
||||
unsigned int
|
||||
config_pollsleep()
|
||||
{
|
||||
return gateway.pollsleep;
|
||||
}
|
||||
|
||||
|
||||
static struct {
|
||||
char *logname;
|
||||
logfile_id_t logfile;
|
||||
@ -1126,9 +1151,20 @@ static int
|
||||
handle_global_item(const char *name, const char *value)
|
||||
{
|
||||
int i;
|
||||
if (strcmp(name, "threads") == 0) {
|
||||
if (strcmp(name, "threads") == 0)
|
||||
{
|
||||
gateway.n_threads = atoi(value);
|
||||
} else {
|
||||
}
|
||||
else if (strcmp(name, "non_blocking_polls") == 0)
|
||||
{
|
||||
gateway.n_nbpoll = atoi(value);
|
||||
}
|
||||
else if (strcmp(name, "poll_sleep") == 0)
|
||||
{
|
||||
gateway.pollsleep = atoi(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; lognames[i].logname; i++)
|
||||
{
|
||||
if (strcasecmp(name, lognames[i].logname) == 0)
|
||||
@ -1150,6 +1186,8 @@ static void
|
||||
global_defaults()
|
||||
{
|
||||
gateway.n_threads = 1;
|
||||
gateway.n_nbpoll = DEFAULT_NBPOLLS;
|
||||
gateway.pollsleep = DEFAULT_POLLSLEEP;
|
||||
if (version_string != NULL)
|
||||
gateway.version_string = strdup(version_string);
|
||||
else
|
||||
|
@ -44,6 +44,9 @@ MEMLOG *plog;
|
||||
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
|
||||
int number_poll_spins;
|
||||
int max_poll_sleep;
|
||||
|
||||
/**
|
||||
* @file poll.c - Abstraction of the epoll functionality
|
||||
*
|
||||
@ -70,7 +73,7 @@ extern int lm_enabled_logfiles_bitmask;
|
||||
/**
|
||||
* Control the use of mutexes for the epoll_wait call. Setting to 1 will
|
||||
* cause the epoll_wait calls to be moved under a mutex. This may be useful
|
||||
* for debuggign purposes but should be avoided in general use.
|
||||
* for debugging purposes but should be avoided in general use.
|
||||
*/
|
||||
#define MUTEX_EPOLL 0
|
||||
|
||||
@ -151,6 +154,7 @@ static struct {
|
||||
int evq_pending; /*< Number of pending descriptors in event queue */
|
||||
int evq_max; /*< Maximum event queue length */
|
||||
int wake_evqpending;/*< Woken from epoll_wait with pending events in queue */
|
||||
int blockingpolls; /*< Number of epoll_waits with a timeout specified */
|
||||
} pollStats;
|
||||
|
||||
/**
|
||||
@ -204,6 +208,9 @@ int i;
|
||||
for (i = 0; i < n_avg_samples; i++)
|
||||
evqp_samples[i] = 0.0;
|
||||
|
||||
number_poll_spins = config_nbpolls();
|
||||
max_poll_sleep = config_pollsleep();
|
||||
|
||||
#if PROFILE_POLL
|
||||
plog = memlog_create("EventQueueWaitTime", ML_LONG, 10000);
|
||||
#endif
|
||||
@ -370,7 +377,7 @@ return_rc:
|
||||
* deschedule a process if a timeout is included, but will not do this if a 0 timeout
|
||||
* value is given. this improves performance when the gateway is under heavy load.
|
||||
*
|
||||
* In order to provide a fairer means of sharign the threads between the different
|
||||
* In order to provide a fairer means of sharing the threads between the different
|
||||
* DCB's the poll mechanism has been decoupled from the processing of the events.
|
||||
* The events are now recieved via the epoll_wait call, a queue of DCB's that have
|
||||
* events pending is maintained and as new events arrive the DCB is added to the end
|
||||
@ -383,7 +390,7 @@ return_rc:
|
||||
*
|
||||
* The introduction of the ability to inject "fake" write events into the event queue meant
|
||||
* that there was a possibility to "starve" new events sicne the polling loop would
|
||||
* consume the event queue before lookign for new events. If the DCB that inject
|
||||
* consume the event queue before looking for new events. If the DCB that inject
|
||||
* the fake event then injected another fake event as a result of the first it meant
|
||||
* that new events did not get added to the queue. The strategy has been updated to
|
||||
* not consume the entire event queue, but process one event before doing a non-blocking
|
||||
@ -407,6 +414,7 @@ struct epoll_event events[MAX_EVENTS];
|
||||
int i, nfds, timeout_bias = 1;
|
||||
int thread_id = (int)arg;
|
||||
DCB *zombies = NULL;
|
||||
int poll_spins = 0;
|
||||
|
||||
/** Add this thread to the bitmask of running polling threads */
|
||||
bitmask_set(&poll_mask, thread_id);
|
||||
@ -460,14 +468,18 @@ DCB *zombies = NULL;
|
||||
* We calculate a timeout bias to alter the length of the blocking
|
||||
* call based on the time since we last received an event to process
|
||||
*/
|
||||
else if (nfds == 0 && pollStats.evq_pending > 0)
|
||||
else if (nfds == 0 && pollStats.evq_pending == 0 && poll_spins++ > number_poll_spins)
|
||||
{
|
||||
atomic_add(&pollStats.blockingpolls, 1);
|
||||
nfds = epoll_wait(epoll_fd,
|
||||
events,
|
||||
MAX_EVENTS,
|
||||
(EPOLL_TIMEOUT * timeout_bias) / 10);
|
||||
(max_poll_sleep * timeout_bias) / 10);
|
||||
if (nfds == 0 && pollStats.evq_pending)
|
||||
{
|
||||
atomic_add(&pollStats.wake_evqpending, 1);
|
||||
poll_spins = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -483,6 +495,7 @@ DCB *zombies = NULL;
|
||||
if (nfds > 0)
|
||||
{
|
||||
timeout_bias = 1;
|
||||
poll_spins = 0;
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [poll_waitevents] epoll_wait found %d fds",
|
||||
@ -598,6 +611,34 @@ DCB *zombies = NULL;
|
||||
} /*< while(1) */
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of non-blocking poll cycles that will be done before
|
||||
* a blocking poll will take place. Whenever an event arrives on a thread
|
||||
* or the thread sees a pending event to execute it will reset it's
|
||||
* poll_spin coutn to zero and will then poll with a 0 timeout until the
|
||||
* poll_spin value is greater than the value set here.
|
||||
*
|
||||
* @param nbpolls Number of non-block polls to perform before blocking
|
||||
*/
|
||||
void
|
||||
poll_set_nonblocking_polls(unsigned int nbpolls)
|
||||
{
|
||||
number_poll_spins = nbpolls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum amount of time, in milliseconds, the polling thread
|
||||
* will block before it will wake and check the event queue for work
|
||||
* that may have been added by another thread.
|
||||
*
|
||||
* @param maxwait Maximum wait time in milliseconds
|
||||
*/
|
||||
void
|
||||
poll_set_maxwait(unsigned int maxwait)
|
||||
{
|
||||
max_poll_sleep = maxwait;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process of the queue of DCB's that have outstanding events
|
||||
*
|
||||
@ -654,6 +695,7 @@ uint32_t ev;
|
||||
if (found)
|
||||
{
|
||||
ev = dcb->evq.pending_events;
|
||||
dcb->evq.processing_events = ev;
|
||||
dcb->evq.pending_events = 0;
|
||||
pollStats.evq_pending--;
|
||||
}
|
||||
@ -869,6 +911,8 @@ uint32_t ev;
|
||||
#endif
|
||||
|
||||
spinlock_acquire(&pollqlock);
|
||||
dcb->evq.processing_events = 0;
|
||||
|
||||
if (dcb->evq.pending_events == 0)
|
||||
{
|
||||
/* No pending events so remove from the queue */
|
||||
@ -963,6 +1007,8 @@ int i;
|
||||
|
||||
dcb_printf(dcb, "Number of epoll cycles: %d\n",
|
||||
pollStats.n_polls);
|
||||
dcb_printf(dcb, "Number of epoll cycles with wait: %d\n",
|
||||
pollStats.blockingpolls);
|
||||
dcb_printf(dcb, "Number of read events: %d\n",
|
||||
pollStats.n_read);
|
||||
dcb_printf(dcb, "Number of write events: %d\n",
|
||||
@ -1220,6 +1266,8 @@ uint32_t ev = EPOLLOUT;
|
||||
|
||||
if (DCB_POLL_BUSY(dcb))
|
||||
{
|
||||
if (dcb->evq.pending_events == 0)
|
||||
pollStats.evq_pending++;
|
||||
dcb->evq.pending_events |= ev;
|
||||
}
|
||||
else
|
||||
@ -1271,11 +1319,13 @@ uint32_t ev;
|
||||
return 0;
|
||||
}
|
||||
dcb = eventq;
|
||||
dcb_printf(pdcb, "%16s | %10s | %s\n", "DCB", "Status", "Events");
|
||||
dcb_printf(pdcb, "-----------------+------------+--------------------\n");
|
||||
dcb_printf(pdcb, "%-16s | %-10s | %-18s | %s\n", "DCB", "Status", "Processing Events",
|
||||
"Pending Events");
|
||||
dcb_printf(pdcb, "-----------------+------------+--------------------+-------------------\n");
|
||||
do {
|
||||
dcb_printf(pdcb, "%16p | %10s | %s\n", dcb,
|
||||
dcb_printf(pdcb, "%-16p | %-10s | %-18s | %-18s\n", dcb,
|
||||
dcb->evq.processing ? "Processing" : "Pending",
|
||||
event_to_string(dcb->evq.processing_events),
|
||||
event_to_string(dcb->evq.pending_events));
|
||||
dcb = dcb->evq.next;
|
||||
} while (dcb != eventq);
|
||||
|
@ -29,10 +29,13 @@
|
||||
* 21/06/13 Mark Riddoch Initial implementation
|
||||
* 07/05/14 Massimiliano Pinto Added version_string to global configuration
|
||||
* 23/05/14 Massimiliano Pinto Added id to global configuration
|
||||
* 17/10/14 Mark Riddoch Added poll tuning configuration parameters
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
#define DEFAULT_NBPOLLS 3 /**< Default number of non block polls before we block */
|
||||
#define DEFAULT_POLLSLEEP 1000 /**< Default poll wait time (milliseconds) */
|
||||
/**
|
||||
* Maximum length for configuration parameter value.
|
||||
*/
|
||||
@ -92,11 +95,15 @@ typedef struct {
|
||||
int n_threads; /**< Number of polling threads */
|
||||
char *version_string; /**< The version string of embedded database library */
|
||||
unsigned long id; /**< MaxScale ID */
|
||||
unsigned int n_nbpoll; /**< Tune number of non-blocking polls */
|
||||
unsigned int pollsleep; /**< Wait time in blocking polls */
|
||||
} GATEWAY_CONF;
|
||||
|
||||
extern int config_load(char *);
|
||||
extern int config_reload();
|
||||
extern int config_threadcount();
|
||||
extern unsigned int config_nbpolls();
|
||||
extern unsigned int config_pollsleep();
|
||||
CONFIG_PARAMETER* config_get_param(CONFIG_PARAMETER* params, const char* name);
|
||||
config_param_type_t config_get_paramtype(CONFIG_PARAMETER* param);
|
||||
CONFIG_PARAMETER* config_clone_param(CONFIG_PARAMETER* param);
|
||||
|
@ -105,6 +105,7 @@ typedef struct gw_protocol {
|
||||
* next The next DCB in the event queue
|
||||
* prev The previous DCB in the event queue
|
||||
* pending_events The events that are pending processing
|
||||
* processing_events The evets currently being processed
|
||||
* processing Flag to indicate the processing status of the DCB
|
||||
* eventqlock Spinlock to protect this structure
|
||||
* inserted Insertion time for logging purposes
|
||||
@ -113,6 +114,7 @@ typedef struct {
|
||||
struct dcb *next;
|
||||
struct dcb *prev;
|
||||
uint32_t pending_events;
|
||||
uint32_t processing_events;
|
||||
int processing;
|
||||
SPINLOCK eventqlock;
|
||||
unsigned long inserted;
|
||||
|
@ -32,7 +32,6 @@
|
||||
* @endverbatim
|
||||
*/
|
||||
#define MAX_EVENTS 1000
|
||||
#define EPOLL_TIMEOUT 1000 /**< The epoll timeout in milliseconds */
|
||||
|
||||
extern void poll_init();
|
||||
extern int poll_add_dcb(DCB *);
|
||||
@ -40,6 +39,8 @@ extern int poll_remove_dcb(DCB *);
|
||||
extern void poll_waitevents(void *);
|
||||
extern void poll_shutdown();
|
||||
extern GWBITMASK *poll_bitmask();
|
||||
extern void poll_set_maxwait(unsigned int);
|
||||
extern void poll_set_nonblocking_polls(unsigned int);
|
||||
extern void dprintPollStats(DCB *);
|
||||
extern void dShowThreads(DCB *dcb);
|
||||
extern void dShowEventQ(DCB *dcb);
|
||||
|
@ -66,6 +66,7 @@
|
||||
#include <adminusers.h>
|
||||
#include <monitor.h>
|
||||
#include <debugcli.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include <skygw_utils.h>
|
||||
#include <log_manager.h>
|
||||
@ -81,6 +82,7 @@
|
||||
#define ARG_TYPE_DCB 7
|
||||
#define ARG_TYPE_MONITOR 8
|
||||
#define ARG_TYPE_FILTER 9
|
||||
#define ARG_TYPE_NUMERIC 10
|
||||
|
||||
/**
|
||||
* The subcommand structure
|
||||
@ -286,6 +288,8 @@ struct subcommand restartoptions[] = {
|
||||
};
|
||||
|
||||
static void set_server(DCB *dcb, SERVER *server, char *bit);
|
||||
static void set_pollsleep(DCB *dcb, int);
|
||||
static void set_nbpoll(DCB *dcb, int);
|
||||
/**
|
||||
* The subcommands of the set command
|
||||
*/
|
||||
@ -294,6 +298,15 @@ struct subcommand setoptions[] = {
|
||||
"Set the status of a server. E.g. set server dbnode4 master",
|
||||
"Set the status of a server. E.g. set server 0x4838320 master",
|
||||
{ARG_TYPE_SERVER, ARG_TYPE_STRING, 0} },
|
||||
{ "pollsleep", 1, set_pollsleep,
|
||||
"Set the maximum poll sleep period in milliseconds",
|
||||
"Set the maximum poll sleep period in milliseconds",
|
||||
{ARG_TYPE_NUMERIC, 0, 0} },
|
||||
{ "nbpolls", 1, set_nbpoll,
|
||||
"Set the number of non-blocking polls",
|
||||
"Set the number of non-blocking polls",
|
||||
{ARG_TYPE_NUMERIC, 0, 0} },
|
||||
|
||||
{ NULL, 0, NULL, NULL, NULL,
|
||||
{0, 0, 0} }
|
||||
};
|
||||
@ -577,6 +590,16 @@ SERVICE *service;
|
||||
if (mode == CLIM_USER || (rval = (unsigned long)strtol(arg, NULL, 0)) == 0)
|
||||
rval = (unsigned long)filter_find(arg);
|
||||
return rval;
|
||||
case ARG_TYPE_NUMERIC:
|
||||
{
|
||||
int i;
|
||||
for (i = 0; arg[i]; i++)
|
||||
{
|
||||
if (arg[i] < '0' || arg[i] > '9')
|
||||
return 0;
|
||||
}
|
||||
return atoi(arg);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -1117,6 +1140,30 @@ static void disable_log_action(DCB *dcb, char *arg1) {
|
||||
skygw_log_disable(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the duration of the sleep passed to the poll wait
|
||||
*
|
||||
* @param dcb DCB for output
|
||||
* @param sleeptime Sleep time in milliseconds
|
||||
*/
|
||||
static void
|
||||
set_pollsleep(DCB *dcb, int sleeptime)
|
||||
{
|
||||
poll_set_maxwait(sleeptime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of non-blockign spins to make
|
||||
*
|
||||
* @param dcb DCB for output
|
||||
* @param nb Number of spins
|
||||
*/
|
||||
static void
|
||||
set_nbpoll(DCB *dcb, int nb)
|
||||
{
|
||||
poll_set_nonblocking_polls(nb);
|
||||
}
|
||||
|
||||
#if defined(SS_DEBUG)
|
||||
static void fail_backendfd(void)
|
||||
{
|
||||
|
Reference in New Issue
Block a user