summaryrefslogtreecommitdiffstats
path: root/lib/workqueue.c
diff options
context:
space:
mode:
authorDonald Sharp <sharpd@cumulusnetworks.com>2015-05-20 02:58:10 +0200
committerDonald Sharp <sharpd@cumulusnetworks.com>2015-05-20 02:58:10 +0200
commit50596be0d5ff65c79060bcd858cda33a974a0dc1 (patch)
tree4c5532f9924f9afc47af95d3cdfa7141e4e901c9 /lib/workqueue.c
parentAdd replace-as option to remove-private-as (diff)
downloadfrr-50596be0d5ff65c79060bcd858cda33a974a0dc1.tar.xz
frr-50596be0d5ff65c79060bcd858cda33a974a0dc1.zip
Some small enhancements to thread and workqueue libraries in zebra:
- Allow work queues to specify the yield duration for corresponding background thread - Support using specified yield duration in thread yielding - During work queue processing, if using a single list element with a meta-queue (like done in Zebra), do not exit after each element is processed, instead update the next-node upon a WQ_REQUEUE so that the WQ processing continues and is terminated by the yield logic. - Enhance work queue debug output
Diffstat (limited to 'lib/workqueue.c')
-rw-r--r--lib/workqueue.c37
1 files changed, 26 insertions, 11 deletions
diff --git a/lib/workqueue.c b/lib/workqueue.c
index 61643bf81..a7f4b7071 100644
--- a/lib/workqueue.c
+++ b/lib/workqueue.c
@@ -84,6 +84,7 @@ work_queue_new (struct thread_master *m, const char *queue_name)
/* Default values, can be overriden by caller */
new->spec.hold = WORK_QUEUE_DEFAULT_HOLD;
+ new->spec.yield = THREAD_YIELD_TIME_SLOT;
return new;
}
@@ -113,6 +114,9 @@ work_queue_schedule (struct work_queue *wq, unsigned int delay)
{
wq->thread = thread_add_background (wq->master, work_queue_run,
wq, delay);
+ /* set thread yield time, if needed */
+ if (wq->thread && wq->spec.yield != THREAD_YIELD_TIME_SLOT)
+ thread_set_yield_time (wq->thread, wq->spec.yield);
return 1;
}
else
@@ -174,27 +178,27 @@ DEFUN(show_work_queues,
struct work_queue *wq;
vty_out (vty,
- "%c %8s %5s %8s %21s%s",
- ' ', "List","(ms) ","Q. Runs","Cycle Counts ",
+ "%c %8s %5s %8s %8s %21s%s",
+ ' ', "List","(ms) ","Q. Runs","Yields","Cycle Counts ",
VTY_NEWLINE);
vty_out (vty,
- "%c %8s %5s %8s %7s %6s %6s %s%s",
+ "%c %8s %5s %8s %8s %7s %6s %8s %6s %s%s",
'P',
"Items",
"Hold",
- "Total",
- "Best","Gran.","Avg.",
+ "Total","Total",
+ "Best","Gran.","Total","Avg.",
"Name",
VTY_NEWLINE);
for (ALL_LIST_ELEMENTS_RO ((&work_queues), node, wq))
{
- vty_out (vty,"%c %8d %5d %8ld %7d %6d %6u %s%s",
+ vty_out (vty,"%c %8d %5d %8ld %8ld %7d %6d %8ld %6u %s%s",
(CHECK_FLAG (wq->flags, WQ_UNPLUGGED) ? ' ' : 'P'),
listcount (wq->items),
wq->spec.hold,
- wq->runs,
- wq->cycles.best, wq->cycles.granularity,
+ wq->runs, wq->yields,
+ wq->cycles.best, wq->cycles.granularity, wq->cycles.total,
(wq->runs) ?
(unsigned int) (wq->cycles.total / wq->runs) : 0,
wq->name,
@@ -250,7 +254,8 @@ work_queue_run (struct thread *thread)
assert (wq && wq->items);
/* calculate cycle granularity:
- * list iteration == 1 cycle
+ * list iteration == 1 run
+ * listnode processing == 1 cycle
* granularity == # cycles between checks whether we should yield.
*
* granularity should be > 0, and can increase slowly after each run to
@@ -309,6 +314,14 @@ work_queue_run (struct thread *thread)
{
item->ran--;
work_queue_item_requeue (wq, node);
+ /* If a single node is being used with a meta-queue (e.g., zebra),
+ * update the next node as we don't want to exit the thread and
+ * reschedule it after every node. By definition, WQ_REQUEUE is
+ * meant to continue the processing; the yield logic will kick in
+ * to terminate the thread when time has exceeded.
+ */
+ if (nnode == NULL)
+ nnode = node;
break;
}
case WQ_RETRY_NOW:
@@ -346,7 +359,7 @@ stats:
/* we yielded, check whether granularity should be reduced */
if (yielded && (cycles < wq->cycles.granularity))
{
- wq->cycles.granularity = ((cycles > 0) ? cycles
+ wq->cycles.granularity = ((cycles > 0) ? cycles
: WORK_QUEUE_MIN_GRANULARITY);
}
/* otherwise, should granularity increase? */
@@ -354,7 +367,7 @@ stats:
{
if (cycles > wq->cycles.best)
wq->cycles.best = cycles;
-
+
/* along with yielded check, provides hysteresis for granularity */
if (cycles > (wq->cycles.granularity * WQ_HYSTERESIS_FACTOR
* WQ_HYSTERESIS_FACTOR))
@@ -366,6 +379,8 @@ stats:
wq->runs++;
wq->cycles.total += cycles;
+ if (yielded)
+ wq->yields++;
#if 0
printf ("%s: cycles %d, new: best %d, worst %d\n",