* [PATCH 0/7] Lazy workqueues v2
@ 2009-08-24 7:56 Jens Axboe
2009-08-24 7:56 ` [PATCH 1/7] workqueue: replace singlethread/freezable/rt parameters and variables with flags Jens Axboe
` (6 more replies)
0 siblings, 7 replies; 14+ messages in thread
From: Jens Axboe @ 2009-08-24 7:56 UTC (permalink / raw)
To: linux-kernel; +Cc: jeff, benh, htejun, bzolnier, alan, akpm
Hi,
This is version #2 of the lazy workqueue patchset. Changes since
the initial (v1) posting:
- Attempt to close a few of the races with exiting threads. I have
not completely audited it yet, but it should be a lot better now
at least.
- Fix a bug with wq barrier work not setting CPU correctly.
- Fix a bug with remote work sometimes being completed on both the
local and remote workqueue thread.
- Fix a compile error introduced with LOCKDEP enabled.
- Make the sleep schedule timeout be 1 jiffy longer than the lazy
exit interval, otherwise we would be going through two sleep cycles
without doing anything before the thread would be deemed OK to exit.
- One more conversion to lazy workqueues (bio-integrity).
Patches are against 2.6.31-rc7.
--
Jens Axboe
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 1/7] workqueue: replace singlethread/freezable/rt parameters and variables with flags
2009-08-24 7:56 [PATCH 0/7] Lazy workqueues v2 Jens Axboe
@ 2009-08-24 7:56 ` Jens Axboe
2009-08-24 7:56 ` [PATCH 2/7] workqueue: add support for lazy workqueues Jens Axboe
` (5 subsequent siblings)
6 siblings, 0 replies; 14+ messages in thread
From: Jens Axboe @ 2009-08-24 7:56 UTC (permalink / raw)
To: linux-kernel; +Cc: jeff, benh, htejun, bzolnier, alan, akpm, Jens Axboe
Collapse the three ints into a flags variable, in preparation for
adding another flag.
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
---
include/linux/workqueue.h | 32 ++++++++++++++++++--------------
kernel/workqueue.c | 22 ++++++++--------------
2 files changed, 26 insertions(+), 28 deletions(-)
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index 13e1adf..ab5a16d 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -165,12 +165,17 @@ struct execute_work {
extern struct workqueue_struct *
-__create_workqueue_key(const char *name, int singlethread,
- int freezeable, int rt, struct lock_class_key *key,
- const char *lock_name);
+__create_workqueue_key(const char *name, unsigned int flags,
+ struct lock_class_key *key, const char *lock_name);
+
+enum {
+ WQ_F_SINGLETHREAD = 1,
+ WQ_F_FREEZABLE = 2,
+ WQ_F_RT = 4,
+};
#ifdef CONFIG_LOCKDEP
-#define __create_workqueue(name, singlethread, freezeable, rt) \
+#define __create_workqueue(name, flags) \
({ \
static struct lock_class_key __key; \
const char *__lock_name; \
@@ -180,20 +185,19 @@ __create_workqueue_key(const char *name, int singlethread,
else \
__lock_name = #name; \
\
- __create_workqueue_key((name), (singlethread), \
- (freezeable), (rt), &__key, \
- __lock_name); \
+ __create_workqueue_key((name), (flags), &__key, __lock_name); \
})
#else
-#define __create_workqueue(name, singlethread, freezeable, rt) \
- __create_workqueue_key((name), (singlethread), (freezeable), (rt), \
- NULL, NULL)
+#define __create_workqueue(name, flags) \
+ __create_workqueue_key((name), (flags), NULL, NULL)
#endif
-#define create_workqueue(name) __create_workqueue((name), 0, 0, 0)
-#define create_rt_workqueue(name) __create_workqueue((name), 0, 0, 1)
-#define create_freezeable_workqueue(name) __create_workqueue((name), 1, 1, 0)
-#define create_singlethread_workqueue(name) __create_workqueue((name), 1, 0, 0)
+#define create_workqueue(name) __create_workqueue((name), 0)
+#define create_rt_workqueue(name) __create_workqueue((name), WQ_F_RT)
+#define create_freezeable_workqueue(name) \
+ __create_workqueue((name), WQ_F_SINGLETHREAD | WQ_F_FREEZABLE)
+#define create_singlethread_workqueue(name) \
+ __create_workqueue((name), WQ_F_SINGLETHREAD)
extern void destroy_workqueue(struct workqueue_struct *wq);
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 0668795..02ba7c9 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -60,9 +60,7 @@ struct workqueue_struct {
struct cpu_workqueue_struct *cpu_wq;
struct list_head list;
const char *name;
- int singlethread;
- int freezeable; /* Freeze threads during suspend */
- int rt;
+ unsigned int flags; /* WQ_F_* flags */
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
@@ -84,9 +82,9 @@ static const struct cpumask *cpu_singlethread_map __read_mostly;
static cpumask_var_t cpu_populated_map __read_mostly;
/* If it's single threaded, it isn't in the list of workqueues. */
-static inline int is_wq_single_threaded(struct workqueue_struct *wq)
+static inline bool is_wq_single_threaded(struct workqueue_struct *wq)
{
- return wq->singlethread;
+ return wq->flags & WQ_F_SINGLETHREAD;
}
static const struct cpumask *wq_cpu_map(struct workqueue_struct *wq)
@@ -314,7 +312,7 @@ static int worker_thread(void *__cwq)
struct cpu_workqueue_struct *cwq = __cwq;
DEFINE_WAIT(wait);
- if (cwq->wq->freezeable)
+ if (cwq->wq->flags & WQ_F_FREEZABLE)
set_freezable();
set_user_nice(current, -5);
@@ -768,7 +766,7 @@ static int create_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
*/
if (IS_ERR(p))
return PTR_ERR(p);
- if (cwq->wq->rt)
+ if (cwq->wq->flags & WQ_F_RT)
sched_setscheduler_nocheck(p, SCHED_FIFO, ¶m);
cwq->thread = p;
@@ -789,9 +787,7 @@ static void start_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
}
struct workqueue_struct *__create_workqueue_key(const char *name,
- int singlethread,
- int freezeable,
- int rt,
+ unsigned int flags,
struct lock_class_key *key,
const char *lock_name)
{
@@ -811,12 +807,10 @@ struct workqueue_struct *__create_workqueue_key(const char *name,
wq->name = name;
lockdep_init_map(&wq->lockdep_map, lock_name, key, 0);
- wq->singlethread = singlethread;
- wq->freezeable = freezeable;
- wq->rt = rt;
+ wq->flags = flags;
INIT_LIST_HEAD(&wq->list);
- if (singlethread) {
+ if (flags & WQ_F_SINGLETHREAD) {
cwq = init_cpu_workqueue(wq, singlethread_cpu);
err = create_workqueue_thread(cwq, singlethread_cpu);
start_workqueue_thread(cwq, -1);
--
1.6.4.173.g3f189
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 2/7] workqueue: add support for lazy workqueues
2009-08-24 7:56 [PATCH 0/7] Lazy workqueues v2 Jens Axboe
2009-08-24 7:56 ` [PATCH 1/7] workqueue: replace singlethread/freezable/rt parameters and variables with flags Jens Axboe
@ 2009-08-24 7:56 ` Jens Axboe
2009-08-24 7:56 ` [PATCH 3/7] crypto: use " Jens Axboe
` (4 subsequent siblings)
6 siblings, 0 replies; 14+ messages in thread
From: Jens Axboe @ 2009-08-24 7:56 UTC (permalink / raw)
To: linux-kernel; +Cc: jeff, benh, htejun, bzolnier, alan, akpm, Jens Axboe
Lazy workqueues are like normal workqueues, except they don't
start a thread per CPU by default. Instead threads are started
when they are needed, and exit when they have been idle for
some time.
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
---
include/linux/workqueue.h | 5 +
kernel/workqueue.c | 203 +++++++++++++++++++++++++++++++++++++++++---
2 files changed, 194 insertions(+), 14 deletions(-)
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index ab5a16d..44cdd3c 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -32,6 +32,7 @@ struct work_struct {
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
+ unsigned int cpu;
};
#define WORK_DATA_INIT() ATOMIC_LONG_INIT(0)
@@ -172,6 +173,7 @@ enum {
WQ_F_SINGLETHREAD = 1,
WQ_F_FREEZABLE = 2,
WQ_F_RT = 4,
+ WQ_F_LAZY = 8,
};
#ifdef CONFIG_LOCKDEP
@@ -198,6 +200,7 @@ enum {
__create_workqueue((name), WQ_F_SINGLETHREAD | WQ_F_FREEZABLE)
#define create_singlethread_workqueue(name) \
__create_workqueue((name), WQ_F_SINGLETHREAD)
+#define create_lazy_workqueue(name) __create_workqueue((name), WQ_F_LAZY)
extern void destroy_workqueue(struct workqueue_struct *wq);
@@ -211,6 +214,8 @@ extern int queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
extern void flush_workqueue(struct workqueue_struct *wq);
extern void flush_scheduled_work(void);
+extern void workqueue_set_lazy_timeout(struct workqueue_struct *wq,
+ unsigned long timeout);
extern int schedule_work(struct work_struct *work);
extern int schedule_work_on(int cpu, struct work_struct *work);
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 02ba7c9..8aba6a4 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -61,11 +61,17 @@ struct workqueue_struct {
struct list_head list;
const char *name;
unsigned int flags; /* WQ_F_* flags */
+ unsigned long lazy_timeout;
+ unsigned int core_cpu;
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
+/* Default lazy workqueue timeout */
+#define WQ_DEF_LAZY_TIMEOUT (60 * HZ)
+
+
/* Serializes the accesses to the list of workqueues. */
static DEFINE_SPINLOCK(workqueue_lock);
static LIST_HEAD(workqueues);
@@ -81,6 +87,8 @@ static const struct cpumask *cpu_singlethread_map __read_mostly;
*/
static cpumask_var_t cpu_populated_map __read_mostly;
+static int create_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu);
+
/* If it's single threaded, it isn't in the list of workqueues. */
static inline bool is_wq_single_threaded(struct workqueue_struct *wq)
{
@@ -138,14 +146,37 @@ static void insert_work(struct cpu_workqueue_struct *cwq,
wake_up(&cwq->more_work);
}
+static inline bool wq_is_lazy(struct workqueue_struct *wq)
+{
+ return wq->flags & WQ_F_LAZY;
+}
+
static void __queue_work(struct cpu_workqueue_struct *cwq,
struct work_struct *work)
{
+ struct workqueue_struct *wq = cwq->wq;
unsigned long flags;
- spin_lock_irqsave(&cwq->lock, flags);
- insert_work(cwq, work, &cwq->worklist);
- spin_unlock_irqrestore(&cwq->lock, flags);
+ /*
+ * This is a lazy workqueue and this particular CPU thread has
+ * exited. We can't create it from here, so add this work on our
+ * static thread. It will create this thread and move the work there.
+ */
+ if (wq_is_lazy(wq) && !cwq->thread) {
+ struct cpu_workqueue_struct *__cwq;
+
+ local_irq_save(flags);
+ __cwq = wq_per_cpu(wq, wq->core_cpu);
+ work->cpu = smp_processor_id();
+ spin_lock(&__cwq->lock);
+ insert_work(__cwq, work, &__cwq->worklist);
+ spin_unlock_irqrestore(&__cwq->lock, flags);
+ } else {
+ spin_lock_irqsave(&cwq->lock, flags);
+ work->cpu = smp_processor_id();
+ insert_work(cwq, work, &cwq->worklist);
+ spin_unlock_irqrestore(&cwq->lock, flags);
+ }
}
/**
@@ -259,13 +290,16 @@ int queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
}
EXPORT_SYMBOL_GPL(queue_delayed_work_on);
-static void run_workqueue(struct cpu_workqueue_struct *cwq)
+static bool run_workqueue(struct cpu_workqueue_struct *cwq)
{
+ bool did_work = false;
+
spin_lock_irq(&cwq->lock);
while (!list_empty(&cwq->worklist)) {
struct work_struct *work = list_entry(cwq->worklist.next,
struct work_struct, entry);
work_func_t f = work->func;
+ int cpu;
#ifdef CONFIG_LOCKDEP
/*
* It is permissible to free the struct work_struct
@@ -279,8 +313,51 @@ static void run_workqueue(struct cpu_workqueue_struct *cwq)
#endif
trace_workqueue_execution(cwq->thread, work);
cwq->current_work = work;
- list_del_init(cwq->worklist.next);
+ list_del_init(&work->entry);
+ cpu = smp_processor_id();
spin_unlock_irq(&cwq->lock);
+ did_work = true;
+
+ /*
+ * If work->cpu isn't us, then we need to create the target
+ * workqueue thread (if someone didn't already do that) and
+ * move the work over there.
+ */
+ if (wq_is_lazy(cwq->wq) && work->cpu != cpu) {
+ struct cpu_workqueue_struct *__cwq;
+ struct task_struct *p;
+ int err;
+
+ /*
+ * Create new thread if we don't already have one
+ * and move the work there. If we fail, fall through
+ * and let this thread handle it
+ */
+ __cwq = wq_per_cpu(cwq->wq, work->cpu);
+ spin_lock_irq(&__cwq->lock);
+ p = __cwq->thread;
+ spin_unlock_irq(&__cwq->lock);
+
+ if (!p)
+ err = create_workqueue_thread(__cwq, work->cpu);
+
+ spin_lock_irq(&__cwq->lock);
+ p = __cwq->thread;
+ if (p) {
+ insert_work(__cwq, work, &__cwq->worklist);
+ spin_unlock_irq(&__cwq->lock);
+ kthread_bind(p, work->cpu);
+ wake_up_process(p);
+ work = NULL;
+ } else
+ spin_unlock_irq(&__cwq->lock);
+ }
+
+ if (!work) {
+ spin_lock_irq(&cwq->lock);
+ cwq->current_work = NULL;
+ continue;
+ }
BUG_ON(get_wq_data(work) != cwq);
work_clear_pending(work);
@@ -305,24 +382,44 @@ static void run_workqueue(struct cpu_workqueue_struct *cwq)
cwq->current_work = NULL;
}
spin_unlock_irq(&cwq->lock);
+ return did_work;
}
static int worker_thread(void *__cwq)
{
struct cpu_workqueue_struct *cwq = __cwq;
+ struct workqueue_struct *wq = cwq->wq;
+ unsigned long last_active = jiffies;
DEFINE_WAIT(wait);
+ int may_exit;
- if (cwq->wq->flags & WQ_F_FREEZABLE)
+ if (wq->flags & WQ_F_FREEZABLE)
set_freezable();
set_user_nice(current, -5);
+ /*
+ * Allow exit if this isn't our core thread
+ */
+ if (wq_is_lazy(wq) && smp_processor_id() != wq->core_cpu)
+ may_exit = 1;
+ else
+ may_exit = 0;
+
for (;;) {
+ int did_work;
+
prepare_to_wait(&cwq->more_work, &wait, TASK_INTERRUPTIBLE);
if (!freezing(current) &&
!kthread_should_stop() &&
- list_empty(&cwq->worklist))
- schedule();
+ list_empty(&cwq->worklist)) {
+ unsigned long timeout = wq->lazy_timeout;
+
+ if (timeout && may_exit)
+ schedule_timeout(timeout + 1);
+ else
+ schedule();
+ }
finish_wait(&cwq->more_work, &wait);
try_to_freeze();
@@ -330,9 +427,29 @@ static int worker_thread(void *__cwq)
if (kthread_should_stop())
break;
- run_workqueue(cwq);
+ did_work = run_workqueue(cwq);
+ if (!may_exit)
+ continue;
+
+ /*
+ * If we did no work for the defined timeout period and we are
+ * allowed to exit, do so.
+ */
+ if (did_work)
+ last_active = jiffies;
+ else if (time_after(jiffies, last_active + wq->lazy_timeout)) {
+ spin_lock_irq(&cwq->lock);
+ cwq->thread = NULL;
+ spin_unlock_irq(&cwq->lock);
+ break;
+ }
}
+ /*
+ * Thread is marked as gone now, re-check if work got added
+ * between deciding to exit and really exiting
+ */
+ run_workqueue(cwq);
return 0;
}
@@ -355,6 +472,7 @@ static void insert_wq_barrier(struct cpu_workqueue_struct *cwq,
init_completion(&barr->done);
+ barr->work.cpu = smp_processor_id();
insert_work(cwq, &barr->work, head);
}
@@ -744,6 +862,7 @@ init_cpu_workqueue(struct workqueue_struct *wq, int cpu)
spin_lock_init(&cwq->lock);
INIT_LIST_HEAD(&cwq->worklist);
init_waitqueue_head(&cwq->more_work);
+ cwq->thread = NULL;
return cwq;
}
@@ -756,6 +875,7 @@ static int create_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
struct task_struct *p;
p = kthread_create(worker_thread, cwq, fmt, wq->name, cpu);
+
/*
* Nobody can add the work_struct to this cwq,
* if (caller is __create_workqueue)
@@ -766,11 +886,23 @@ static int create_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
*/
if (IS_ERR(p))
return PTR_ERR(p);
- if (cwq->wq->flags & WQ_F_RT)
+ if (wq->flags & WQ_F_RT)
sched_setscheduler_nocheck(p, SCHED_FIFO, ¶m);
- cwq->thread = p;
- trace_workqueue_creation(cwq->thread, cpu);
+ spin_lock_irq(&cwq->lock);
+ if (!cwq->thread) {
+ cwq->thread = p;
+ p = NULL;
+ }
+ spin_unlock_irq(&cwq->lock);
+
+ /*
+ * If we raced on the thread creation, kill the new task
+ */
+ if (p)
+ kthread_stop(p);
+ else
+ trace_workqueue_creation(cwq->thread, cpu);
return 0;
}
@@ -814,7 +946,10 @@ struct workqueue_struct *__create_workqueue_key(const char *name,
cwq = init_cpu_workqueue(wq, singlethread_cpu);
err = create_workqueue_thread(cwq, singlethread_cpu);
start_workqueue_thread(cwq, -1);
+ wq->core_cpu = singlethread_cpu;
} else {
+ int created = 0;
+
cpu_maps_update_begin();
/*
* We must place this wq on list even if the code below fails.
@@ -833,10 +968,16 @@ struct workqueue_struct *__create_workqueue_key(const char *name,
*/
for_each_possible_cpu(cpu) {
cwq = init_cpu_workqueue(wq, cpu);
- if (err || !cpu_online(cpu))
+ if (err || !cpu_online(cpu) ||
+ (created && wq_is_lazy(wq)))
continue;
err = create_workqueue_thread(cwq, cpu);
start_workqueue_thread(cwq, cpu);
+ if (!err) {
+ if (!created)
+ wq->core_cpu = cpu;
+ created++;
+ }
}
cpu_maps_update_done();
}
@@ -844,7 +985,9 @@ struct workqueue_struct *__create_workqueue_key(const char *name,
if (err) {
destroy_workqueue(wq);
wq = NULL;
- }
+ } else if (wq_is_lazy(wq))
+ workqueue_set_lazy_timeout(wq, WQ_DEF_LAZY_TIMEOUT);
+
return wq;
}
EXPORT_SYMBOL_GPL(__create_workqueue_key);
@@ -877,6 +1020,13 @@ static void cleanup_workqueue_thread(struct cpu_workqueue_struct *cwq)
cwq->thread = NULL;
}
+static bool hotplug_should_start_thread(struct workqueue_struct *wq, int cpu)
+{
+ if (wq_is_lazy(wq) && cpu != wq->core_cpu)
+ return 0;
+ return 1;
+}
+
/**
* destroy_workqueue - safely terminate a workqueue
* @wq: target workqueue
@@ -923,6 +1073,8 @@ undo:
switch (action) {
case CPU_UP_PREPARE:
+ if (!hotplug_should_start_thread(wq, cpu))
+ break;
if (!create_workqueue_thread(cwq, cpu))
break;
printk(KERN_ERR "workqueue [%s] for %i failed\n",
@@ -932,6 +1084,8 @@ undo:
goto undo;
case CPU_ONLINE:
+ if (!hotplug_should_start_thread(wq, cpu))
+ break;
start_workqueue_thread(cwq, cpu);
break;
@@ -999,6 +1153,27 @@ long work_on_cpu(unsigned int cpu, long (*fn)(void *), void *arg)
EXPORT_SYMBOL_GPL(work_on_cpu);
#endif /* CONFIG_SMP */
+/**
+ * workqueue_set_lazy_timeout - set lazy exit timeout
+ * @wq: the associated workqueue_struct
+ * @timeout: timeout in jiffies
+ *
+ * This will set the timeout for a lazy workqueue. If no work has been
+ * processed for @timeout jiffies, then the workqueue is allowed to exit.
+ * It will be dynamically created again when work is queued to it.
+ *
+ * Note that this only works for workqueues created with
+ * create_lazy_workqueue().
+ */
+void workqueue_set_lazy_timeout(struct workqueue_struct *wq,
+ unsigned long timeout)
+{
+ if (WARN_ON(!wq_is_lazy(wq)))
+ return;
+
+ wq->lazy_timeout = timeout;
+}
+
void __init init_workqueues(void)
{
alloc_cpumask_var(&cpu_populated_map, GFP_KERNEL);
--
1.6.4.173.g3f189
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 3/7] crypto: use lazy workqueues
2009-08-24 7:56 [PATCH 0/7] Lazy workqueues v2 Jens Axboe
2009-08-24 7:56 ` [PATCH 1/7] workqueue: replace singlethread/freezable/rt parameters and variables with flags Jens Axboe
2009-08-24 7:56 ` [PATCH 2/7] workqueue: add support for lazy workqueues Jens Axboe
@ 2009-08-24 7:56 ` Jens Axboe
2009-08-24 7:56 ` [PATCH 4/7] libata: use lazy workqueues for the pio task Jens Axboe
` (3 subsequent siblings)
6 siblings, 0 replies; 14+ messages in thread
From: Jens Axboe @ 2009-08-24 7:56 UTC (permalink / raw)
To: linux-kernel; +Cc: jeff, benh, htejun, bzolnier, alan, akpm, Jens Axboe
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
---
crypto/crypto_wq.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/crypto/crypto_wq.c b/crypto/crypto_wq.c
index fdcf624..88cccee 100644
--- a/crypto/crypto_wq.c
+++ b/crypto/crypto_wq.c
@@ -20,7 +20,7 @@ EXPORT_SYMBOL_GPL(kcrypto_wq);
static int __init crypto_wq_init(void)
{
- kcrypto_wq = create_workqueue("crypto");
+ kcrypto_wq = create_lazy_workqueue("crypto");
if (unlikely(!kcrypto_wq))
return -ENOMEM;
return 0;
--
1.6.4.173.g3f189
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 4/7] libata: use lazy workqueues for the pio task
2009-08-24 7:56 [PATCH 0/7] Lazy workqueues v2 Jens Axboe
` (2 preceding siblings ...)
2009-08-24 7:56 ` [PATCH 3/7] crypto: use " Jens Axboe
@ 2009-08-24 7:56 ` Jens Axboe
2009-08-24 16:32 ` Jeff Garzik
2009-08-24 7:56 ` [PATCH 5/7] aio: use lazy workqueues Jens Axboe
` (2 subsequent siblings)
6 siblings, 1 reply; 14+ messages in thread
From: Jens Axboe @ 2009-08-24 7:56 UTC (permalink / raw)
To: linux-kernel; +Cc: jeff, benh, htejun, bzolnier, alan, akpm, Jens Axboe
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
---
drivers/ata/libata-core.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 072ba5e..35f74c9 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -6580,7 +6580,7 @@ static int __init ata_init(void)
{
ata_parse_force_param();
- ata_wq = create_workqueue("ata");
+ ata_wq = create_lazy_workqueue("ata");
if (!ata_wq)
goto free_force_tbl;
--
1.6.4.173.g3f189
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 5/7] aio: use lazy workqueues
2009-08-24 7:56 [PATCH 0/7] Lazy workqueues v2 Jens Axboe
` (3 preceding siblings ...)
2009-08-24 7:56 ` [PATCH 4/7] libata: use lazy workqueues for the pio task Jens Axboe
@ 2009-08-24 7:56 ` Jens Axboe
2009-08-24 7:56 ` [PATCH 6/7] sunrpc: " Jens Axboe
2009-08-24 7:56 ` [PATCH 7/7] bio: convert integrity to " Jens Axboe
6 siblings, 0 replies; 14+ messages in thread
From: Jens Axboe @ 2009-08-24 7:56 UTC (permalink / raw)
To: linux-kernel; +Cc: jeff, benh, htejun, bzolnier, alan, akpm, Jens Axboe
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
---
fs/aio.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/fs/aio.c b/fs/aio.c
index d065b2c..4103b59 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -72,7 +72,7 @@ static int __init aio_setup(void)
kiocb_cachep = KMEM_CACHE(kiocb, SLAB_HWCACHE_ALIGN|SLAB_PANIC);
kioctx_cachep = KMEM_CACHE(kioctx,SLAB_HWCACHE_ALIGN|SLAB_PANIC);
- aio_wq = create_workqueue("aio");
+ aio_wq = create_lazy_workqueue("aio");
pr_debug("aio_setup: sizeof(struct page) = %d\n", (int)sizeof(struct page));
--
1.6.4.173.g3f189
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 6/7] sunrpc: use lazy workqueues
2009-08-24 7:56 [PATCH 0/7] Lazy workqueues v2 Jens Axboe
` (4 preceding siblings ...)
2009-08-24 7:56 ` [PATCH 5/7] aio: use lazy workqueues Jens Axboe
@ 2009-08-24 7:56 ` Jens Axboe
2009-08-24 7:56 ` [PATCH 7/7] bio: convert integrity to " Jens Axboe
6 siblings, 0 replies; 14+ messages in thread
From: Jens Axboe @ 2009-08-24 7:56 UTC (permalink / raw)
To: linux-kernel; +Cc: jeff, benh, htejun, bzolnier, alan, akpm, Jens Axboe
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
---
net/sunrpc/sched.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index 8f459ab..ce99fe2 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -970,7 +970,7 @@ static int rpciod_start(void)
* Create the rpciod thread and wait for it to start.
*/
dprintk("RPC: creating workqueue rpciod\n");
- wq = create_workqueue("rpciod");
+ wq = create_lazy_workqueue("rpciod");
rpciod_workqueue = wq;
return rpciod_workqueue != NULL;
}
--
1.6.4.173.g3f189
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 7/7] bio: convert integrity to lazy workqueues
2009-08-24 7:56 [PATCH 0/7] Lazy workqueues v2 Jens Axboe
` (5 preceding siblings ...)
2009-08-24 7:56 ` [PATCH 6/7] sunrpc: " Jens Axboe
@ 2009-08-24 7:56 ` Jens Axboe
6 siblings, 0 replies; 14+ messages in thread
From: Jens Axboe @ 2009-08-24 7:56 UTC (permalink / raw)
To: linux-kernel; +Cc: jeff, benh, htejun, bzolnier, alan, akpm, Jens Axboe
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
---
fs/bio-integrity.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/fs/bio-integrity.c b/fs/bio-integrity.c
index 49a34e7..cfd256e 100644
--- a/fs/bio-integrity.c
+++ b/fs/bio-integrity.c
@@ -780,7 +780,7 @@ void __init bio_integrity_init(void)
{
unsigned int i;
- kintegrityd_wq = create_workqueue("kintegrityd");
+ kintegrityd_wq = create_lazy_workqueue("kintegrityd");
if (!kintegrityd_wq)
panic("Failed to create kintegrityd\n");
--
1.6.4.173.g3f189
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 4/7] libata: use lazy workqueues for the pio task
2009-08-24 7:56 ` [PATCH 4/7] libata: use lazy workqueues for the pio task Jens Axboe
@ 2009-08-24 16:32 ` Jeff Garzik
2009-08-24 16:42 ` Jens Axboe
2009-08-24 16:45 ` John Stoffel
0 siblings, 2 replies; 14+ messages in thread
From: Jeff Garzik @ 2009-08-24 16:32 UTC (permalink / raw)
To: Jens Axboe; +Cc: linux-kernel, benh, htejun, bzolnier, alan, akpm
On 08/24/2009 03:56 AM, Jens Axboe wrote:
> Signed-off-by: Jens Axboe<jens.axboe@oracle.com>
> ---
> drivers/ata/libata-core.c | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
> index 072ba5e..35f74c9 100644
> --- a/drivers/ata/libata-core.c
> +++ b/drivers/ata/libata-core.c
> @@ -6580,7 +6580,7 @@ static int __init ata_init(void)
> {
> ata_parse_force_param();
>
> - ata_wq = create_workqueue("ata");
> + ata_wq = create_lazy_workqueue("ata");
> if (!ata_wq)
> goto free_force_tbl;
No objections to the code, operationally...
But it is disappointing that the "1 thread on UP" problem is not solved
while changing this libata area. Is there no way to specify a minimum
lazy-thread count?
A key problem continues to be tying to the number of CPUs, which is
quite inappropriate for libata.
Jeff
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 4/7] libata: use lazy workqueues for the pio task
2009-08-24 16:32 ` Jeff Garzik
@ 2009-08-24 16:42 ` Jens Axboe
2009-08-24 16:51 ` Jeff Garzik
2009-08-24 16:45 ` John Stoffel
1 sibling, 1 reply; 14+ messages in thread
From: Jens Axboe @ 2009-08-24 16:42 UTC (permalink / raw)
To: Jeff Garzik; +Cc: linux-kernel, benh, htejun, bzolnier, alan, akpm
On Mon, Aug 24 2009, Jeff Garzik wrote:
> On 08/24/2009 03:56 AM, Jens Axboe wrote:
>> Signed-off-by: Jens Axboe<jens.axboe@oracle.com>
>> ---
>> drivers/ata/libata-core.c | 2 +-
>> 1 files changed, 1 insertions(+), 1 deletions(-)
>>
>> diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
>> index 072ba5e..35f74c9 100644
>> --- a/drivers/ata/libata-core.c
>> +++ b/drivers/ata/libata-core.c
>> @@ -6580,7 +6580,7 @@ static int __init ata_init(void)
>> {
>> ata_parse_force_param();
>>
>> - ata_wq = create_workqueue("ata");
>> + ata_wq = create_lazy_workqueue("ata");
>> if (!ata_wq)
>> goto free_force_tbl;
>
> No objections to the code, operationally...
>
> But it is disappointing that the "1 thread on UP" problem is not solved
> while changing this libata area. Is there no way to specify a minimum
> lazy-thread count?
>
> A key problem continues to be tying to the number of CPUs, which is
> quite inappropriate for libata.
We'll solve that next, the first problem is reducing the per-cpu
threads. Lots of places use per-cpu workqueues because that is what is
available, not necessarily because it's an appropriate choice. Like the
ata_wq above, it's not even a good fit.
--
Jens Axboe
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 4/7] libata: use lazy workqueues for the pio task
2009-08-24 16:32 ` Jeff Garzik
2009-08-24 16:42 ` Jens Axboe
@ 2009-08-24 16:45 ` John Stoffel
2009-08-24 16:52 ` Jeff Garzik
1 sibling, 1 reply; 14+ messages in thread
From: John Stoffel @ 2009-08-24 16:45 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Jens Axboe, linux-kernel, benh, htejun, bzolnier, alan, akpm
>>>>> "Jeff" == Jeff Garzik <jeff@garzik.org> writes:
Jeff> On 08/24/2009 03:56 AM, Jens Axboe wrote:
>> Signed-off-by: Jens Axboe<jens.axboe@oracle.com>
>> ---
>> drivers/ata/libata-core.c | 2 +-
>> 1 files changed, 1 insertions(+), 1 deletions(-)
>>
>> diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
>> index 072ba5e..35f74c9 100644
>> --- a/drivers/ata/libata-core.c
>> +++ b/drivers/ata/libata-core.c
>> @@ -6580,7 +6580,7 @@ static int __init ata_init(void)
>> {
>> ata_parse_force_param();
>>
>> - ata_wq = create_workqueue("ata");
>> + ata_wq = create_lazy_workqueue("ata");
>> if (!ata_wq)
>> goto free_force_tbl;
Jeff> No objections to the code, operationally...
Jeff> But it is disappointing that the "1 thread on UP" problem is not
Jeff> solved while changing this libata area. Is there no way to
Jeff> specify a minimum lazy-thread count?
Jeff> A key problem continues to be tying to the number of CPUs, which
Jeff> is quite inappropriate for libata.
So should the minimum number be the NumATADisks on the system? Actual
or potential? I've got a system with dual CPUs and two IDE disk, two
SATA disks and two SCSI disks, plus two SCSI Tape drives. All on
seperate controllers... how would that work?
John
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 4/7] libata: use lazy workqueues for the pio task
2009-08-24 16:42 ` Jens Axboe
@ 2009-08-24 16:51 ` Jeff Garzik
2009-08-24 18:16 ` Jens Axboe
0 siblings, 1 reply; 14+ messages in thread
From: Jeff Garzik @ 2009-08-24 16:51 UTC (permalink / raw)
To: Jens Axboe; +Cc: linux-kernel, benh, htejun, bzolnier, alan, akpm
On 08/24/2009 12:42 PM, Jens Axboe wrote:
> On Mon, Aug 24 2009, Jeff Garzik wrote:
>> No objections to the code, operationally...
>>
>> But it is disappointing that the "1 thread on UP" problem is not solved
>> while changing this libata area. Is there no way to specify a minimum
>> lazy-thread count?
>>
>> A key problem continues to be tying to the number of CPUs, which is
>> quite inappropriate for libata.
>
> We'll solve that next, the first problem is reducing the per-cpu
> threads. Lots of places use per-cpu workqueues because that is what is
> available, not necessarily because it's an appropriate choice. Like the
> ata_wq above, it's not even a good fit.
Agreed + sounds great.
Thanks -- both for hacking libata for this, and more generally, for
attacking the too-many-kthreads problem! :) It's just sad how many
unused workqueue threads hang about, on every modern Linux box.
Jeff
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 4/7] libata: use lazy workqueues for the pio task
2009-08-24 16:45 ` John Stoffel
@ 2009-08-24 16:52 ` Jeff Garzik
0 siblings, 0 replies; 14+ messages in thread
From: Jeff Garzik @ 2009-08-24 16:52 UTC (permalink / raw)
To: John Stoffel; +Cc: Jens Axboe, linux-kernel, benh, htejun, bzolnier, alan, akpm
On 08/24/2009 12:45 PM, John Stoffel wrote:
>>>>>> "Jeff" == Jeff Garzik<jeff@garzik.org> writes:
> Jeff> No objections to the code, operationally...
>
> Jeff> But it is disappointing that the "1 thread on UP" problem is not
> Jeff> solved while changing this libata area. Is there no way to
> Jeff> specify a minimum lazy-thread count?
>
> Jeff> A key problem continues to be tying to the number of CPUs, which
> Jeff> is quite inappropriate for libata.
>
> So should the minimum number be the NumATADisks on the system? Actual
> or potential? I've got a system with dual CPUs and two IDE disk, two
> SATA disks and two SCSI disks, plus two SCSI Tape drives. All on
> seperate controllers... how would that work?
Technically speaking, the maximum is the number of PIO-polling devices.
Theoretically this can change with hotplugging, but that is _very_ rare
-- mainly PATA+media bay situations, or bridged SATA with an ancient
PATA device.
Jeff
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 4/7] libata: use lazy workqueues for the pio task
2009-08-24 16:51 ` Jeff Garzik
@ 2009-08-24 18:16 ` Jens Axboe
0 siblings, 0 replies; 14+ messages in thread
From: Jens Axboe @ 2009-08-24 18:16 UTC (permalink / raw)
To: Jeff Garzik; +Cc: linux-kernel, benh, htejun, bzolnier, alan, akpm
On Mon, Aug 24 2009, Jeff Garzik wrote:
> On 08/24/2009 12:42 PM, Jens Axboe wrote:
>> On Mon, Aug 24 2009, Jeff Garzik wrote:
>>> No objections to the code, operationally...
>>>
>>> But it is disappointing that the "1 thread on UP" problem is not solved
>>> while changing this libata area. Is there no way to specify a minimum
>>> lazy-thread count?
>>>
>>> A key problem continues to be tying to the number of CPUs, which is
>>> quite inappropriate for libata.
>>
>> We'll solve that next, the first problem is reducing the per-cpu
>> threads. Lots of places use per-cpu workqueues because that is what is
>> available, not necessarily because it's an appropriate choice. Like the
>> ata_wq above, it's not even a good fit.
>
> Agreed + sounds great.
>
> Thanks -- both for hacking libata for this, and more generally, for
> attacking the too-many-kthreads problem! :) It's just sad how many
> unused workqueue threads hang about, on every modern Linux box.
It is, it's one of those problems that's gotten totally out of hand. A
handful of wasted threads is easily ignored, but once you are safely
into the three digits it's just too much.
I took a quick look at converting libata to slow-work, and it's an easy
fit (and would solve the UP problem too). The remaining piece is a
slow_work_enqueue_delayed(), since we do use pio task queue with a small
delay from one path.
So I hope that we can get by with slow-work with a few tweaks here and
there, and just retain workqueues for the true performance (or
persistent) case. The lazy workqueues is still a nice addition I think,
since they don't hang around forever when things go idle.
--
Jens Axboe
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2009-08-24 18:16 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-08-24 7:56 [PATCH 0/7] Lazy workqueues v2 Jens Axboe
2009-08-24 7:56 ` [PATCH 1/7] workqueue: replace singlethread/freezable/rt parameters and variables with flags Jens Axboe
2009-08-24 7:56 ` [PATCH 2/7] workqueue: add support for lazy workqueues Jens Axboe
2009-08-24 7:56 ` [PATCH 3/7] crypto: use " Jens Axboe
2009-08-24 7:56 ` [PATCH 4/7] libata: use lazy workqueues for the pio task Jens Axboe
2009-08-24 16:32 ` Jeff Garzik
2009-08-24 16:42 ` Jens Axboe
2009-08-24 16:51 ` Jeff Garzik
2009-08-24 18:16 ` Jens Axboe
2009-08-24 16:45 ` John Stoffel
2009-08-24 16:52 ` Jeff Garzik
2009-08-24 7:56 ` [PATCH 5/7] aio: use lazy workqueues Jens Axboe
2009-08-24 7:56 ` [PATCH 6/7] sunrpc: " Jens Axboe
2009-08-24 7:56 ` [PATCH 7/7] bio: convert integrity to " Jens Axboe
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.