Add a new taskqueue setup method that takes a cpuid to pin the

taskqueue worker thread(s) to.

For now it isn't a taskqueue/taskthread error to fail to pin
to the given cpuid.

Thanks to rpaulo@, kib@ and jhb@ for feedback.

Tested:

* igb(4), with local RSS patches to pin taskqueues.

TODO:

* ask the doc team for help in documenting the new API call.
* add a taskqueue_start_threads_cpuset() method which takes
  a cpuset_t - but this may require a bunch of surgery to
  bring cpuset_t into scope.
This commit is contained in:
Adrian Chadd 2014-05-24 20:37:15 +00:00
parent 6fea75b4be
commit 5a6f0eee47
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=266629
2 changed files with 60 additions and 9 deletions

View File

@ -30,6 +30,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/cpuset.h>
#include <sys/interrupt.h>
#include <sys/kernel.h>
#include <sys/kthread.h>
@ -496,25 +497,19 @@ taskqueue_swi_giant_run(void *dummy)
taskqueue_run(taskqueue_swi_giant);
}
int
taskqueue_start_threads(struct taskqueue **tqp, int count, int pri,
const char *name, ...)
static int
_taskqueue_start_threads(struct taskqueue **tqp, int count, int pri,
cpuset_t *mask, const char *ktname)
{
va_list ap;
struct thread *td;
struct taskqueue *tq;
int i, error;
char ktname[MAXCOMLEN + 1];
if (count <= 0)
return (EINVAL);
tq = *tqp;
va_start(ap, name);
vsnprintf(ktname, sizeof(ktname), name, ap);
va_end(ap);
tq->tq_threads = malloc(sizeof(struct thread *) * count, M_TASKQUEUE,
M_NOWAIT | M_ZERO);
if (tq->tq_threads == NULL) {
@ -542,6 +537,19 @@ taskqueue_start_threads(struct taskqueue **tqp, int count, int pri,
if (tq->tq_threads[i] == NULL)
continue;
td = tq->tq_threads[i];
if (mask) {
error = cpuset_setthread(curthread->td_tid, mask);
/*
* Failing to pin is rarely an actual fatal error;
* it'll just affect performance.
*/
if (error)
printf("%s: curthread=%llu: can't pin; "
"error=%d\n",
__func__,
(unsigned long long) td->td_tid,
error);
}
thread_lock(td);
sched_prio(td, pri);
sched_add(td, SRQ_BORING);
@ -551,6 +559,45 @@ taskqueue_start_threads(struct taskqueue **tqp, int count, int pri,
return (0);
}
int
taskqueue_start_threads(struct taskqueue **tqp, int count, int pri,
const char *name, ...)
{
char ktname[MAXCOMLEN + 1];
va_list ap;
va_start(ap, name);
vsnprintf(ktname, sizeof(ktname), name, ap);
va_end(ap);
return (_taskqueue_start_threads(tqp, count, pri, NULL, ktname));
}
int
taskqueue_start_threads_pinned(struct taskqueue **tqp, int count, int pri,
int cpu_id, const char *name, ...)
{
char ktname[MAXCOMLEN + 1];
va_list ap;
cpuset_t mask;
va_start(ap, name);
vsnprintf(ktname, sizeof(ktname), name, ap);
va_end(ap);
/*
* In case someone passes in NOCPU, just fall back to the
* default behaviour of "don't pin".
*/
if (cpu_id != NOCPU) {
CPU_ZERO(&mask);
CPU_SET(cpu_id, &mask);
}
return (_taskqueue_start_threads(tqp, count, pri,
cpu_id == NOCPU ? NULL : &mask, ktname));
}
static inline void
taskqueue_run_callback(struct taskqueue *tq,
enum taskqueue_callback_type cb_type)

View File

@ -71,6 +71,10 @@ struct taskqueue *taskqueue_create(const char *name, int mflags,
void *context);
int taskqueue_start_threads(struct taskqueue **tqp, int count, int pri,
const char *name, ...) __printflike(4, 5);
int taskqueue_start_threads_pinned(struct taskqueue **tqp, int count,
int pri, int cpu_id, const char *name,
...) __printflike(5, 6);
int taskqueue_enqueue(struct taskqueue *queue, struct task *task);
int taskqueue_enqueue_timeout(struct taskqueue *queue,
struct timeout_task *timeout_task, int ticks);