summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/command.c2
-rw-r--r--lib/prefix.c9
-rw-r--r--lib/table.c14
-rw-r--r--lib/thread.c142
-rw-r--r--lib/thread.h3
-rw-r--r--lib/workqueue.c17
6 files changed, 151 insertions, 36 deletions
diff --git a/lib/command.c b/lib/command.c
index 478125f2..5a13f39c 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -3650,6 +3650,8 @@ cmd_init (int terminal)
install_element (VIEW_NODE, &show_thread_cpu_cmd);
install_element (ENABLE_NODE, &show_thread_cpu_cmd);
install_element (RESTRICTED_NODE, &show_thread_cpu_cmd);
+
+ install_element (ENABLE_NODE, &clear_thread_cpu_cmd);
install_element (VIEW_NODE, &show_work_queues_cmd);
install_element (ENABLE_NODE, &show_work_queues_cmd);
}
diff --git a/lib/prefix.c b/lib/prefix.c
index 7dc866d1..61a278ca 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -70,15 +70,16 @@ prefix_match (const struct prefix *n, const struct prefix *p)
{
int offset;
int shift;
-
- /* Set both prefix's head pointer. */
- const u_char *np = (const u_char *)&n->u.prefix;
- const u_char *pp = (const u_char *)&p->u.prefix;
+ const u_char *np, *pp;
/* If n's prefix is longer than p's one return 0. */
if (n->prefixlen > p->prefixlen)
return 0;
+ /* Set both prefix's head pointer. */
+ np = (const u_char *)&n->u.prefix;
+ pp = (const u_char *)&p->u.prefix;
+
offset = n->prefixlen / PNBBY;
shift = n->prefixlen % PNBBY;
diff --git a/lib/table.c b/lib/table.c
index 04df3af5..e40e6707 100644
--- a/lib/table.c
+++ b/lib/table.c
@@ -209,6 +209,10 @@ route_node_match (const struct route_table *table, const struct prefix *p)
{
if (node->info)
matched = node;
+
+ if (node->p.prefixlen == p->prefixlen)
+ break;
+
node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)];
}
@@ -260,8 +264,8 @@ route_node_lookup (struct route_table *table, struct prefix *p)
while (node && node->p.prefixlen <= p->prefixlen &&
prefix_match (&node->p, p))
{
- if (node->p.prefixlen == p->prefixlen && node->info)
- return route_lock_node (node);
+ if (node->p.prefixlen == p->prefixlen)
+ return node->info ? route_lock_node (node) : NULL;
node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)];
}
@@ -283,10 +287,8 @@ route_node_get (struct route_table *table, struct prefix *p)
prefix_match (&node->p, p))
{
if (node->p.prefixlen == p->prefixlen)
- {
- route_lock_node (node);
- return node;
- }
+ return route_lock_node (node);
+
match = node;
node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)];
}
diff --git a/lib/thread.c b/lib/thread.c
index e89af541..fd841c21 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -303,7 +303,7 @@ cpu_record_print(struct vty *vty, thread_type filter)
void *args[3] = {&tmp, vty, &filter};
memset(&tmp, 0, sizeof tmp);
- tmp.funcname = "TOTAL";
+ tmp.funcname = (char *)"TOTAL";
tmp.types = filter;
#ifdef HAVE_RUSAGE
@@ -382,6 +382,89 @@ DEFUN(show_thread_cpu,
cpu_record_print(vty, filter);
return CMD_SUCCESS;
}
+
+static void
+cpu_record_hash_clear (struct hash_backet *bucket,
+ void *args)
+{
+ thread_type *filter = args;
+ struct cpu_thread_history *a = bucket->data;
+
+ a = bucket->data;
+ if ( !(a->types & *filter) )
+ return;
+
+ hash_release (cpu_record, bucket->data);
+}
+
+static void
+cpu_record_clear (thread_type filter)
+{
+ thread_type *tmp = &filter;
+ hash_iterate (cpu_record,
+ (void (*) (struct hash_backet*,void*)) cpu_record_hash_clear,
+ tmp);
+}
+
+DEFUN(clear_thread_cpu,
+ clear_thread_cpu_cmd,
+ "clear thread cpu [FILTER]",
+ "Clear stored data\n"
+ "Thread information\n"
+ "Thread CPU usage\n"
+ "Display filter (rwtexb)\n")
+{
+ int i = 0;
+ thread_type filter = (thread_type) -1U;
+
+ if (argc > 0)
+ {
+ filter = 0;
+ while (argv[0][i] != '\0')
+ {
+ switch ( argv[0][i] )
+ {
+ case 'r':
+ case 'R':
+ filter |= (1 << THREAD_READ);
+ break;
+ case 'w':
+ case 'W':
+ filter |= (1 << THREAD_WRITE);
+ break;
+ case 't':
+ case 'T':
+ filter |= (1 << THREAD_TIMER);
+ break;
+ case 'e':
+ case 'E':
+ filter |= (1 << THREAD_EVENT);
+ break;
+ case 'x':
+ case 'X':
+ filter |= (1 << THREAD_EXECUTE);
+ break;
+ case 'b':
+ case 'B':
+ filter |= (1 << THREAD_BACKGROUND);
+ break;
+ default:
+ break;
+ }
+ ++i;
+ }
+ if (filter == 0)
+ {
+ vty_out(vty, "Invalid filter \"%s\" specified,"
+ " must contain at least one of 'RWTEXB'%s",
+ argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+
+ cpu_record_clear (filter);
+ return CMD_SUCCESS;
+}
/* List allocation and head/tail print out. */
static void
@@ -903,6 +986,24 @@ thread_timer_process (struct thread_list *list, struct timeval *timenow)
return ready;
}
+/* process a list en masse, e.g. for event thread lists */
+static unsigned int
+thread_process (struct thread_list *list)
+{
+ struct thread *thread;
+ unsigned int ready = 0;
+
+ for (thread = list->head; thread; thread = thread->next)
+ {
+ thread_list_delete (list, thread);
+ thread->type = THREAD_READY;
+ thread_list_add (&thread->master->ready, thread);
+ ready++;
+ }
+ return ready;
+}
+
+
/* Fetch next ready thread. */
struct thread *
thread_fetch (struct thread_master *m, struct thread *fetch)
@@ -911,41 +1012,48 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
fd_set readfd;
fd_set writefd;
fd_set exceptfd;
- struct timeval timer_val;
+ struct timeval timer_val = { .tv_sec = 0, .tv_usec = 0 };
struct timeval timer_val_bg;
- struct timeval *timer_wait;
+ struct timeval *timer_wait = &timer_val;
struct timeval *timer_wait_bg;
while (1)
{
int num = 0;
- /* Signals are highest priority */
+ /* Signals pre-empt everything */
quagga_sigevent_process ();
- /* Normal event are the next highest priority. */
- if ((thread = thread_trim_head (&m->event)) != NULL)
- return thread_run (m, thread, fetch);
-
- /* If there are any ready threads from previous scheduler runs,
- * process top of them.
+ /* Drain the ready queue of already scheduled jobs, before scheduling
+ * more.
*/
if ((thread = thread_trim_head (&m->ready)) != NULL)
return thread_run (m, thread, fetch);
+ /* To be fair to all kinds of threads, and avoid starvation, we
+ * need to be careful to consider all thread types for scheduling
+ * in each quanta. I.e. we should not return early from here on.
+ */
+
+ /* Normal event are the next highest priority. */
+ thread_process (&m->event);
+
/* Structure copy. */
readfd = m->readfd;
writefd = m->writefd;
exceptfd = m->exceptfd;
/* Calculate select wait timer if nothing else to do */
- quagga_get_relative (NULL);
- timer_wait = thread_timer_wait (&m->timer, &timer_val);
- timer_wait_bg = thread_timer_wait (&m->background, &timer_val_bg);
-
- if (timer_wait_bg &&
- (!timer_wait || (timeval_cmp (*timer_wait, *timer_wait_bg) > 0)))
- timer_wait = timer_wait_bg;
+ if (m->ready.count == 0)
+ {
+ quagga_get_relative (NULL);
+ timer_wait = thread_timer_wait (&m->timer, &timer_val);
+ timer_wait_bg = thread_timer_wait (&m->background, &timer_val_bg);
+
+ if (timer_wait_bg &&
+ (!timer_wait || (timeval_cmp (*timer_wait, *timer_wait_bg) > 0)))
+ timer_wait = timer_wait_bg;
+ }
num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait);
diff --git a/lib/thread.h b/lib/thread.h
index b52bc541..978aa6b0 100644
--- a/lib/thread.h
+++ b/lib/thread.h
@@ -82,7 +82,7 @@ struct thread
struct cpu_thread_history
{
int (*func)(struct thread *);
- const char *funcname;
+ char *funcname;
unsigned int total_calls;
struct time_stats
{
@@ -197,6 +197,7 @@ extern int thread_should_yield (struct thread *);
/* Internal libzebra exports */
extern void thread_getrusage (RUSAGE_T *);
extern struct cmd_element show_thread_cpu_cmd;
+extern struct cmd_element clear_thread_cpu_cmd;
/* replacements for the system gettimeofday(), clock_gettime() and
* time() functions, providing support for non-decrementing clock on
diff --git a/lib/workqueue.c b/lib/workqueue.c
index 7c811edd..52b5f41c 100644
--- a/lib/workqueue.c
+++ b/lib/workqueue.c
@@ -341,7 +341,7 @@ work_queue_run (struct thread *thread)
stats:
-#define WQ_HYSTERIS_FACTOR 2
+#define WQ_HYSTERESIS_FACTOR 4
/* we yielded, check whether granularity should be reduced */
if (yielded && (cycles < wq->cycles.granularity))
@@ -349,17 +349,18 @@ stats:
wq->cycles.granularity = ((cycles > 0) ? cycles
: WORK_QUEUE_MIN_GRANULARITY);
}
-
- if (cycles >= (wq->cycles.granularity))
+ /* otherwise, should granularity increase? */
+ else if (cycles >= (wq->cycles.granularity))
{
if (cycles > wq->cycles.best)
wq->cycles.best = cycles;
- /* along with yielded check, provides hysteris for granularity */
- if (cycles > (wq->cycles.granularity * WQ_HYSTERIS_FACTOR * 2))
- wq->cycles.granularity *= WQ_HYSTERIS_FACTOR; /* quick ramp-up */
- else if (cycles > (wq->cycles.granularity * WQ_HYSTERIS_FACTOR))
- wq->cycles.granularity += WQ_HYSTERIS_FACTOR;
+ /* along with yielded check, provides hysteresis for granularity */
+ if (cycles > (wq->cycles.granularity * WQ_HYSTERESIS_FACTOR
+ * WQ_HYSTERESIS_FACTOR))
+ wq->cycles.granularity *= WQ_HYSTERESIS_FACTOR; /* quick ramp-up */
+ else if (cycles > (wq->cycles.granularity * WQ_HYSTERESIS_FACTOR))
+ wq->cycles.granularity += WQ_HYSTERESIS_FACTOR;
}
#undef WQ_HYSTERIS_FACTOR