Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1422263 > unrolled thread
| Started by | Christoph Hellwig <hch@lst.de> |
|---|---|
| First post | 2016-06-14 22:00 +0200 |
| Last post | 2016-06-16 17:30 +0200 |
| Articles | 20 on this page of 29 — 4 participants |
Back to article view | Back to linux.kernel
automatic interrupt affinity for MSI/MSI-X capable devices V2 Christoph Hellwig <hch@lst.de> - 2016-06-14 22:00 +0200
[PATCH 03/13] irq: Add affinity hint to irq allocation Christoph Hellwig <hch@lst.de> - 2016-06-14 22:00 +0200
[PATCH 11/13] blk-mq: allow the driver to pass in an affinity mask Christoph Hellwig <hch@lst.de> - 2016-06-14 22:00 +0200
[PATCH 06/13] irq: add a helper spread an affinity mask for MSI/MSI-X vectors Christoph Hellwig <hch@lst.de> - 2016-06-14 22:00 +0200
Re: [PATCH 06/13] irq: add a helper spread an affinity mask for MSI/MSI-X vectors "Guilherme G. Piccoli" <gpiccoli@linux.vnet.ibm.com> - 2016-06-15 00:00 +0200
Re: [PATCH 06/13] irq: add a helper spread an affinity mask for MSI/MSI-X vectors Christoph Hellwig <hch@lst.de> - 2016-06-15 12:20 +0200
Re: [PATCH 06/13] irq: add a helper spread an affinity mask for MSI/MSI-X vectors "Guilherme G. Piccoli" <gpiccoli@linux.vnet.ibm.com> - 2016-06-15 15:10 +0200
Re: [PATCH 06/13] irq: add a helper spread an affinity mask for MSI/MSI-X vectors Christoph Hellwig <hch@lst.de> - 2016-06-16 17:20 +0200
[PATCH 07/13] pci: Provide sensible irq vector alloc/free routines Christoph Hellwig <hch@lst.de> - 2016-06-14 22:00 +0200
Re: [PATCH 07/13] pci: Provide sensible irq vector alloc/free routines Alexander Gordeev <agordeev@redhat.com> - 2016-06-23 13:20 +0200
[PATCH 02/13] irq: Introduce IRQD_AFFINITY_MANAGED flag Christoph Hellwig <hch@lst.de> - 2016-06-14 22:00 +0200
Re: [PATCH 02/13] irq: Introduce IRQD_AFFINITY_MANAGED flag Christoph Hellwig <hch@lst.de> - 2016-06-15 12:30 +0200
Re: [PATCH 02/13] irq: Introduce IRQD_AFFINITY_MANAGED flag Keith Busch <keith.busch@intel.com> - 2016-06-15 17:10 +0200
Re: [PATCH 02/13] irq: Introduce IRQD_AFFINITY_MANAGED flag Keith Busch <keith.busch@intel.com> - 2016-06-15 18:00 +0200
Re: [PATCH 02/13] irq: Introduce IRQD_AFFINITY_MANAGED flag Keith Busch <keith.busch@intel.com> - 2016-06-15 22:00 +0200
Re: [PATCH 02/13] irq: Introduce IRQD_AFFINITY_MANAGED flag Keith Busch <keith.busch@intel.com> - 2016-06-15 22:10 +0200
Re: [PATCH 02/13] irq: Introduce IRQD_AFFINITY_MANAGED flag Keith Busch <keith.busch@intel.com> - 2016-06-16 17:20 +0200
Re: [PATCH 02/13] irq: Introduce IRQD_AFFINITY_MANAGED flag Alexander Gordeev <agordeev@redhat.com> - 2016-06-22 14:00 +0200
Re: [PATCH 02/13] irq: Introduce IRQD_AFFINITY_MANAGED flag Christoph Hellwig <hch@lst.de> - 2016-06-16 17:30 +0200
Re: [PATCH 02/13] irq: Introduce IRQD_AFFINITY_MANAGED flag Christoph Hellwig <hch@lst.de> - 2016-06-20 14:30 +0200
Re: [PATCH 02/13] irq: Introduce IRQD_AFFINITY_MANAGED flag Christoph Hellwig <hch@lst.de> - 2016-06-21 16:40 +0200
[PATCH 01/13] irq/msi: Remove unused MSI_FLAG_IDENTITY_MAP Christoph Hellwig <hch@lst.de> - 2016-06-14 22:00 +0200
[PATCH 09/13] blk-mq: don't redistribute hardware queues on a CPU hotplug event Christoph Hellwig <hch@lst.de> - 2016-06-14 22:10 +0200
[PATCH 13/13] nvme: remove the post_scan callout Christoph Hellwig <hch@lst.de> - 2016-06-14 22:10 +0200
[PATCH 08/13] pci: spread interrupt vectors in pci_alloc_irq_vectors Christoph Hellwig <hch@lst.de> - 2016-06-14 22:10 +0200
[PATCH 05/13] irq/msi: Make use of affinity aware allocations Christoph Hellwig <hch@lst.de> - 2016-06-14 22:10 +0200
[PATCH 12/13] nvme: switch to use pci_alloc_irq_vectors Christoph Hellwig <hch@lst.de> - 2016-06-14 22:10 +0200
[PATCH 04/13] irq: Use affinity hint in irqdesc allocation Christoph Hellwig <hch@lst.de> - 2016-06-14 22:10 +0200
Re: automatic interrupt affinity for MSI/MSI-X capable devices V2 Christoph Hellwig <hch@lst.de> - 2016-06-16 17:30 +0200
Page 1 of 2 [1] 2 Next page →
| From | Christoph Hellwig <hch@lst.de> |
|---|---|
| Date | 2016-06-14 22:00 +0200 |
| Subject | automatic interrupt affinity for MSI/MSI-X capable devices V2 |
| Message-ID | <rK2Fb-Rz-3@gated-at.bofh.it> |
This series enhances the irq and PCI code to allow spreading around MSI and MSI-X vectors so that they have per-cpu affinity if possible, or at least per-node. For that it takes the algorithm from blk-mq, moves it to a common place, and makes it available through a vastly simplified PCI interrupt allocation API. It then switches blk-mq to be able to pick up the queue mapping from the device if available, and demonstrates all this using the NVMe driver. There also is a git tree available at: git://git.infradead.org/users/hch/block.git Gitweb: http://git.infradead.org/users/hch/block.git/shortlog/refs/heads/msix-spreading.4 Changes since V1: - irq core improvements to properly assign the affinity before request_irq (tglx) - better handling of the MSI vs MSI-X differences in the low level MSI allocator (hch and tglx) - various improvements to pci_alloc_irq_vectors (hch) - remove blk-mq hardware queue reassigned on hotplug cpu events (hch) - forward ported to Jens' current for-next tree (hch)
[toc] | [next] | [standalone]
| From | Christoph Hellwig <hch@lst.de> |
|---|---|
| Date | 2016-06-14 22:00 +0200 |
| Subject | [PATCH 03/13] irq: Add affinity hint to irq allocation |
| Message-ID | <rK2Fc-Rz-9@gated-at.bofh.it> |
| In reply to | #1422263 |
From: Thomas Gleixner <tglx@linutronix.de>
Add an extra argument to the irq(domain) allocation functions, so we can hand
down affinity hints to the allocator. Thats necessary to implement proper
support for multiqueue devices.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
arch/sparc/kernel/irq_64.c | 2 +-
arch/x86/kernel/apic/io_apic.c | 5 +++--
include/linux/irq.h | 4 ++--
include/linux/irqdomain.h | 9 ++++++---
kernel/irq/ipi.c | 2 +-
kernel/irq/irqdesc.c | 12 ++++++++----
kernel/irq/irqdomain.c | 22 ++++++++++++++--------
kernel/irq/manage.c | 7 ++++---
kernel/irq/msi.c | 3 ++-
9 files changed, 41 insertions(+), 25 deletions(-)
diff --git a/arch/sparc/kernel/irq_64.c b/arch/sparc/kernel/irq_64.c
index e22416c..34a7930 100644
--- a/arch/sparc/kernel/irq_64.c
+++ b/arch/sparc/kernel/irq_64.c
@@ -242,7 +242,7 @@ unsigned int irq_alloc(unsigned int dev_handle, unsigned int dev_ino)
{
int irq;
- irq = __irq_alloc_descs(-1, 1, 1, numa_node_id(), NULL);
+ irq = __irq_alloc_descs(-1, 1, 1, numa_node_id(), NULL, NULL);
if (irq <= 0)
goto out;
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 84e33ff..bca0c81 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -981,7 +981,7 @@ static int alloc_irq_from_domain(struct irq_domain *domain, int ioapic, u32 gsi,
return __irq_domain_alloc_irqs(domain, irq, 1,
ioapic_alloc_attr_node(info),
- info, legacy);
+ info, legacy, NULL);
}
/*
@@ -1014,7 +1014,8 @@ static int alloc_isa_irq_from_domain(struct irq_domain *domain,
info->ioapic_pin))
return -ENOMEM;
} else {
- irq = __irq_domain_alloc_irqs(domain, irq, 1, node, info, true);
+ irq = __irq_domain_alloc_irqs(domain, irq, 1, node, info, true,
+ NULL);
if (irq >= 0) {
irq_data = irq_domain_get_irq_data(domain, irq);
data = irq_data->chip_data;
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 49d66d1..63803a4 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -708,11 +708,11 @@ static inline struct cpumask *irq_data_get_affinity_mask(struct irq_data *d)
unsigned int arch_dynirq_lower_bound(unsigned int from);
int __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
- struct module *owner);
+ struct module *owner, const struct cpumask *affinity);
/* use macros to avoid needing export.h for THIS_MODULE */
#define irq_alloc_descs(irq, from, cnt, node) \
- __irq_alloc_descs(irq, from, cnt, node, THIS_MODULE)
+ __irq_alloc_descs(irq, from, cnt, node, THIS_MODULE, NULL)
#define irq_alloc_desc(node) \
irq_alloc_descs(-1, 0, 1, node)
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index f1f36e0..1aee0fb 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -39,6 +39,7 @@ struct irq_domain;
struct of_device_id;
struct irq_chip;
struct irq_data;
+struct cpumask;
/* Number of irqs reserved for a legacy isa controller */
#define NUM_ISA_INTERRUPTS 16
@@ -217,7 +218,8 @@ extern struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec,
enum irq_domain_bus_token bus_token);
extern void irq_set_default_host(struct irq_domain *host);
extern int irq_domain_alloc_descs(int virq, unsigned int nr_irqs,
- irq_hw_number_t hwirq, int node);
+ irq_hw_number_t hwirq, int node,
+ const struct cpumask *affinity);
static inline struct fwnode_handle *of_node_to_fwnode(struct device_node *node)
{
@@ -389,7 +391,7 @@ static inline struct irq_domain *irq_domain_add_hierarchy(struct irq_domain *par
extern int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base,
unsigned int nr_irqs, int node, void *arg,
- bool realloc);
+ bool realloc, const struct cpumask *affinity);
extern void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs);
extern void irq_domain_activate_irq(struct irq_data *irq_data);
extern void irq_domain_deactivate_irq(struct irq_data *irq_data);
@@ -397,7 +399,8 @@ extern void irq_domain_deactivate_irq(struct irq_data *irq_data);
static inline int irq_domain_alloc_irqs(struct irq_domain *domain,
unsigned int nr_irqs, int node, void *arg)
{
- return __irq_domain_alloc_irqs(domain, -1, nr_irqs, node, arg, false);
+ return __irq_domain_alloc_irqs(domain, -1, nr_irqs, node, arg, false,
+ NULL);
}
extern int irq_domain_alloc_irqs_recursive(struct irq_domain *domain,
diff --git a/kernel/irq/ipi.c b/kernel/irq/ipi.c
index 89b49f6..4fd2351 100644
--- a/kernel/irq/ipi.c
+++ b/kernel/irq/ipi.c
@@ -76,7 +76,7 @@ int irq_reserve_ipi(struct irq_domain *domain,
}
}
- virq = irq_domain_alloc_descs(-1, nr_irqs, 0, NUMA_NO_NODE);
+ virq = irq_domain_alloc_descs(-1, nr_irqs, 0, NUMA_NO_NODE, NULL);
if (virq <= 0) {
pr_warn("Can't reserve IPI, failed to alloc descs\n");
return -ENOMEM;
diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c
index 8731e1c..b8df4fc 100644
--- a/kernel/irq/irqdesc.c
+++ b/kernel/irq/irqdesc.c
@@ -223,7 +223,7 @@ static void free_desc(unsigned int irq)
}
static int alloc_descs(unsigned int start, unsigned int cnt, int node,
- struct module *owner)
+ const struct cpumask *affinity, struct module *owner)
{
struct irq_desc *desc;
int i;
@@ -333,6 +333,7 @@ static void free_desc(unsigned int irq)
}
static inline int alloc_descs(unsigned int start, unsigned int cnt, int node,
+ const struct cpumask *affinity,
struct module *owner)
{
u32 i;
@@ -453,12 +454,15 @@ EXPORT_SYMBOL_GPL(irq_free_descs);
* @cnt: Number of consecutive irqs to allocate.
* @node: Preferred node on which the irq descriptor should be allocated
* @owner: Owning module (can be NULL)
+ * @affinity: Optional pointer to an affinity mask which hints where the
+ * irq descriptors should be allocated and which default
+ * affinities to use
*
* Returns the first irq number or error code
*/
int __ref
__irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
- struct module *owner)
+ struct module *owner, const struct cpumask *affinity)
{
int start, ret;
@@ -494,7 +498,7 @@ __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
bitmap_set(allocated_irqs, start, cnt);
mutex_unlock(&sparse_irq_lock);
- return alloc_descs(start, cnt, node, owner);
+ return alloc_descs(start, cnt, node, affinity, owner);
err:
mutex_unlock(&sparse_irq_lock);
@@ -512,7 +516,7 @@ EXPORT_SYMBOL_GPL(__irq_alloc_descs);
*/
unsigned int irq_alloc_hwirqs(int cnt, int node)
{
- int i, irq = __irq_alloc_descs(-1, 0, cnt, node, NULL);
+ int i, irq = __irq_alloc_descs(-1, 0, cnt, node, NULL, NULL);
if (irq < 0)
return 0;
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 8798b6c..79459b7 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -481,7 +481,7 @@ unsigned int irq_create_mapping(struct irq_domain *domain,
}
/* Allocate a virtual interrupt number */
- virq = irq_domain_alloc_descs(-1, 1, hwirq, of_node_to_nid(of_node));
+ virq = irq_domain_alloc_descs(-1, 1, hwirq, of_node_to_nid(of_node), NULL);
if (virq <= 0) {
pr_debug("-> virq allocation failed\n");
return 0;
@@ -835,19 +835,23 @@ const struct irq_domain_ops irq_domain_simple_ops = {
EXPORT_SYMBOL_GPL(irq_domain_simple_ops);
int irq_domain_alloc_descs(int virq, unsigned int cnt, irq_hw_number_t hwirq,
- int node)
+ int node, const struct cpumask *affinity)
{
unsigned int hint;
if (virq >= 0) {
- virq = irq_alloc_descs(virq, virq, cnt, node);
+ virq = __irq_alloc_descs(virq, virq, cnt, node, THIS_MODULE,
+ affinity);
} else {
hint = hwirq % nr_irqs;
if (hint == 0)
hint++;
- virq = irq_alloc_descs_from(hint, cnt, node);
- if (virq <= 0 && hint > 1)
- virq = irq_alloc_descs_from(1, cnt, node);
+ virq = __irq_alloc_descs(-1, hint, cnt, node, THIS_MODULE,
+ affinity);
+ if (virq <= 0 && hint > 1) {
+ virq = __irq_alloc_descs(-1, 1, cnt, node, THIS_MODULE,
+ affinity);
+ }
}
return virq;
@@ -1160,6 +1164,7 @@ int irq_domain_alloc_irqs_recursive(struct irq_domain *domain,
* @node: NUMA node id for memory allocation
* @arg: domain specific argument
* @realloc: IRQ descriptors have already been allocated if true
+ * @affinity: Optional irq affinity mask for multiqueue devices
*
* Allocate IRQ numbers and initialized all data structures to support
* hierarchy IRQ domains.
@@ -1175,7 +1180,7 @@ int irq_domain_alloc_irqs_recursive(struct irq_domain *domain,
*/
int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base,
unsigned int nr_irqs, int node, void *arg,
- bool realloc)
+ bool realloc, const struct cpumask *affinity)
{
int i, ret, virq;
@@ -1193,7 +1198,8 @@ int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base,
if (realloc && irq_base >= 0) {
virq = irq_base;
} else {
- virq = irq_domain_alloc_descs(irq_base, nr_irqs, 0, node);
+ virq = irq_domain_alloc_descs(irq_base, nr_irqs, 0, node,
+ affinity);
if (virq < 0) {
pr_debug("cannot allocate IRQ(base %d, count %d)\n",
irq_base, nr_irqs);
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 30658e9..ad0aac6 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -353,10 +353,11 @@ static int setup_affinity(struct irq_desc *desc, struct cpumask *mask)
return 0;
/*
- * Preserve an userspace affinity setup, but make sure that
- * one of the targets is online.
+ * Preserve the managed affinity setting and an userspace affinity
+ * setup, but make sure that one of the targets is online.
*/
- if (irqd_has_set(&desc->irq_data, IRQD_AFFINITY_SET)) {
+ if (irqd_affinity_is_managed(&desc->irq_data) ||
+ irqd_has_set(&desc->irq_data, IRQD_AFFINITY_SET)) {
if (cpumask_intersects(desc->irq_common_data.affinity,
cpu_online_mask))
set = desc->irq_common_data.affinity;
diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
index eb5bf2b..58dbbac 100644
--- a/kernel/irq/msi.c
+++ b/kernel/irq/msi.c
@@ -334,7 +334,8 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
ops->set_desc(&arg, desc);
virq = __irq_domain_alloc_irqs(domain, -1, desc->nvec_used,
- dev_to_node(dev), &arg, false);
+ dev_to_node(dev), &arg, false,
+ NULL);
if (virq < 0) {
ret = -ENOSPC;
if (ops->handle_error)
--
2.1.4
[toc] | [prev] | [next] | [standalone]
| From | Christoph Hellwig <hch@lst.de> |
|---|---|
| Date | 2016-06-14 22:00 +0200 |
| Subject | [PATCH 11/13] blk-mq: allow the driver to pass in an affinity mask |
| Message-ID | <rK2Fc-Rz-11@gated-at.bofh.it> |
| In reply to | #1422263 |
Allow drivers to pass in the affinity mask from the generic interrupt
layer, and spread queues based on that. If the driver doesn't pass in
a mask we will create it using the genirq helper. As this helper was
modelled after the blk-mq algorithm there should be no change in
behavior.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
block/Makefile | 2 +-
block/blk-mq-cpumap.c | 120 -------------------------------------------------
block/blk-mq.c | 72 ++++++++++++++++++++++++++---
block/blk-mq.h | 8 ----
include/linux/blk-mq.h | 1 +
5 files changed, 69 insertions(+), 134 deletions(-)
delete mode 100644 block/blk-mq-cpumap.c
diff --git a/block/Makefile b/block/Makefile
index 9eda232..aeb318d 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -6,7 +6,7 @@ obj-$(CONFIG_BLOCK) := bio.o elevator.o blk-core.o blk-tag.o blk-sysfs.o \
blk-flush.o blk-settings.o blk-ioc.o blk-map.o \
blk-exec.o blk-merge.o blk-softirq.o blk-timeout.o \
blk-lib.o blk-mq.o blk-mq-tag.o \
- blk-mq-sysfs.o blk-mq-cpu.o blk-mq-cpumap.o ioctl.o \
+ blk-mq-sysfs.o blk-mq-cpu.o ioctl.o \
genhd.o scsi_ioctl.o partition-generic.o ioprio.o \
badblocks.o partitions/
diff --git a/block/blk-mq-cpumap.c b/block/blk-mq-cpumap.c
deleted file mode 100644
index d0634bc..0000000
--- a/block/blk-mq-cpumap.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * CPU <-> hardware queue mapping helpers
- *
- * Copyright (C) 2013-2014 Jens Axboe
- */
-#include <linux/kernel.h>
-#include <linux/threads.h>
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/cpu.h>
-
-#include <linux/blk-mq.h>
-#include "blk.h"
-#include "blk-mq.h"
-
-static int cpu_to_queue_index(unsigned int nr_cpus, unsigned int nr_queues,
- const int cpu)
-{
- return cpu * nr_queues / nr_cpus;
-}
-
-static int get_first_sibling(unsigned int cpu)
-{
- unsigned int ret;
-
- ret = cpumask_first(topology_sibling_cpumask(cpu));
- if (ret < nr_cpu_ids)
- return ret;
-
- return cpu;
-}
-
-int blk_mq_update_queue_map(unsigned int *map, unsigned int nr_queues,
- const struct cpumask *online_mask)
-{
- unsigned int i, nr_cpus, nr_uniq_cpus, queue, first_sibling;
- cpumask_var_t cpus;
-
- if (!alloc_cpumask_var(&cpus, GFP_ATOMIC))
- return 1;
-
- cpumask_clear(cpus);
- nr_cpus = nr_uniq_cpus = 0;
- for_each_cpu(i, online_mask) {
- nr_cpus++;
- first_sibling = get_first_sibling(i);
- if (!cpumask_test_cpu(first_sibling, cpus))
- nr_uniq_cpus++;
- cpumask_set_cpu(i, cpus);
- }
-
- queue = 0;
- for_each_possible_cpu(i) {
- if (!cpumask_test_cpu(i, online_mask)) {
- map[i] = 0;
- continue;
- }
-
- /*
- * Easy case - we have equal or more hardware queues. Or
- * there are no thread siblings to take into account. Do
- * 1:1 if enough, or sequential mapping if less.
- */
- if (nr_queues >= nr_cpus || nr_cpus == nr_uniq_cpus) {
- map[i] = cpu_to_queue_index(nr_cpus, nr_queues, queue);
- queue++;
- continue;
- }
-
- /*
- * Less then nr_cpus queues, and we have some number of
- * threads per cores. Map sibling threads to the same
- * queue.
- */
- first_sibling = get_first_sibling(i);
- if (first_sibling == i) {
- map[i] = cpu_to_queue_index(nr_uniq_cpus, nr_queues,
- queue);
- queue++;
- } else
- map[i] = map[first_sibling];
- }
-
- free_cpumask_var(cpus);
- return 0;
-}
-
-unsigned int *blk_mq_make_queue_map(struct blk_mq_tag_set *set)
-{
- unsigned int *map;
-
- /* If cpus are offline, map them to first hctx */
- map = kzalloc_node(sizeof(*map) * nr_cpu_ids, GFP_KERNEL,
- set->numa_node);
- if (!map)
- return NULL;
-
- if (!blk_mq_update_queue_map(map, set->nr_hw_queues, cpu_online_mask))
- return map;
-
- kfree(map);
- return NULL;
-}
-
-/*
- * We have no quick way of doing reverse lookups. This is only used at
- * queue init time, so runtime isn't important.
- */
-int blk_mq_hw_queue_to_node(unsigned int *mq_map, unsigned int index)
-{
- int i;
-
- for_each_possible_cpu(i) {
- if (index == mq_map[i])
- return local_memory_node(cpu_to_node(i));
- }
-
- return NUMA_NO_NODE;
-}
diff --git a/block/blk-mq.c b/block/blk-mq.c
index 622cb22..6027a49 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -22,6 +22,7 @@
#include <linux/sched/sysctl.h>
#include <linux/delay.h>
#include <linux/crash_dump.h>
+#include <linux/interrupt.h>
#include <trace/events/block.h>
@@ -1954,6 +1955,22 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set)
}
EXPORT_SYMBOL(blk_mq_init_queue);
+/*
+ * We have no quick way of doing reverse lookups. This is only used at
+ * queue init time, so runtime isn't important.
+ */
+static int blk_mq_hw_queue_to_node(unsigned int *mq_map, unsigned int index)
+{
+ int i;
+
+ for_each_possible_cpu(i) {
+ if (index == mq_map[i])
+ return local_memory_node(cpu_to_node(i));
+ }
+
+ return NUMA_NO_NODE;
+}
+
static void blk_mq_realloc_hw_ctxs(struct blk_mq_tag_set *set,
struct request_queue *q)
{
@@ -2253,6 +2270,30 @@ struct cpumask *blk_mq_tags_cpumask(struct blk_mq_tags *tags)
}
EXPORT_SYMBOL_GPL(blk_mq_tags_cpumask);
+static int blk_mq_create_mq_map(struct blk_mq_tag_set *set,
+ const struct cpumask *affinity_mask)
+{
+ int queue = -1, cpu = 0;
+
+ set->mq_map = kzalloc_node(sizeof(*set->mq_map) * nr_cpu_ids,
+ GFP_KERNEL, set->numa_node);
+ if (!set->mq_map)
+ return -ENOMEM;
+
+ if (!affinity_mask)
+ return 0; /* map all cpus to queue 0 */
+
+ /* If cpus are offline, map them to first hctx */
+ for_each_online_cpu(cpu) {
+ if (cpumask_test_cpu(cpu, affinity_mask))
+ queue++;
+ if (queue > 0)
+ set->mq_map[cpu] = queue;
+ }
+
+ return 0;
+}
+
/*
* Alloc a tag set to be associated with one or more request queues.
* May fail with EINVAL for various error conditions. May adjust the
@@ -2261,6 +2302,8 @@ EXPORT_SYMBOL_GPL(blk_mq_tags_cpumask);
*/
int blk_mq_alloc_tag_set(struct blk_mq_tag_set *set)
{
+ int ret;
+
BUILD_BUG_ON(BLK_MQ_MAX_DEPTH > 1 << BLK_MQ_UNIQUE_TAG_BITS);
if (!set->nr_hw_queues)
@@ -2299,11 +2342,30 @@ int blk_mq_alloc_tag_set(struct blk_mq_tag_set *set)
if (!set->tags)
return -ENOMEM;
- set->mq_map = blk_mq_make_queue_map(set);
- if (!set->mq_map)
- goto out_free_tags;
+ /*
+ * Use the passed in affinity mask if the driver provided one.
+ */
+ if (set->affinity_mask) {
+ ret = blk_mq_create_mq_map(set, set->affinity_mask);
+ if (!set->mq_map)
+ goto out_free_tags;
+ } else {
+ struct cpumask *affinity_mask;
- if (blk_mq_alloc_rq_maps(set))
+ ret = irq_create_affinity_mask(&affinity_mask,
+ &set->nr_hw_queues);
+ if (ret)
+ goto out_free_tags;
+
+ ret = blk_mq_create_mq_map(set, affinity_mask);
+ kfree(affinity_mask);
+
+ if (!set->mq_map)
+ goto out_free_tags;
+ }
+
+ ret = blk_mq_alloc_rq_maps(set);
+ if (ret)
goto out_free_mq_map;
mutex_init(&set->tag_list_lock);
@@ -2317,7 +2379,7 @@ out_free_mq_map:
out_free_tags:
kfree(set->tags);
set->tags = NULL;
- return -ENOMEM;
+ return ret;
}
EXPORT_SYMBOL(blk_mq_alloc_tag_set);
diff --git a/block/blk-mq.h b/block/blk-mq.h
index 9087b11..fe7e21f 100644
--- a/block/blk-mq.h
+++ b/block/blk-mq.h
@@ -45,14 +45,6 @@ void blk_mq_enable_hotplug(void);
void blk_mq_disable_hotplug(void);
/*
- * CPU -> queue mappings
- */
-extern unsigned int *blk_mq_make_queue_map(struct blk_mq_tag_set *set);
-extern int blk_mq_update_queue_map(unsigned int *map, unsigned int nr_queues,
- const struct cpumask *online_mask);
-extern int blk_mq_hw_queue_to_node(unsigned int *map, unsigned int);
-
-/*
* sysfs helpers
*/
extern int blk_mq_sysfs_register(struct request_queue *q);
diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h
index 0a3b138..404cc86 100644
--- a/include/linux/blk-mq.h
+++ b/include/linux/blk-mq.h
@@ -75,6 +75,7 @@ struct blk_mq_tag_set {
unsigned int timeout;
unsigned int flags; /* BLK_MQ_F_* */
void *driver_data;
+ struct cpumask *affinity_mask;
struct blk_mq_tags **tags;
--
2.1.4
[toc] | [prev] | [next] | [standalone]
| From | Christoph Hellwig <hch@lst.de> |
|---|---|
| Date | 2016-06-14 22:00 +0200 |
| Subject | [PATCH 06/13] irq: add a helper spread an affinity mask for MSI/MSI-X vectors |
| Message-ID | <rK2Fc-Rz-17@gated-at.bofh.it> |
| In reply to | #1422263 |
This is lifted from the blk-mq code and adopted to use the affinity mask
concept just intruced in the irq handling code.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
include/linux/interrupt.h | 11 +++++++++
kernel/irq/Makefile | 1 +
kernel/irq/affinity.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 72 insertions(+)
create mode 100644 kernel/irq/affinity.c
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 9fcabeb..12003c0 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -278,6 +278,9 @@ extern int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m);
extern int
irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify);
+int irq_create_affinity_mask(struct cpumask **affinity_mask,
+ unsigned int *nr_vecs);
+
#else /* CONFIG_SMP */
static inline int irq_set_affinity(unsigned int irq, const struct cpumask *m)
@@ -308,6 +311,14 @@ irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify)
{
return 0;
}
+
+static inline int irq_create_affinity_mask(struct cpumask **affinity_mask,
+ unsigned int *nr_vecs)
+{
+ *affinity_mask = NULL;
+ *nr_vecs = 1;
+ return 0;
+}
#endif /* CONFIG_SMP */
/*
diff --git a/kernel/irq/Makefile b/kernel/irq/Makefile
index 2ee42e9..1d3ee31 100644
--- a/kernel/irq/Makefile
+++ b/kernel/irq/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_GENERIC_IRQ_MIGRATION) += cpuhotplug.o
obj-$(CONFIG_PM_SLEEP) += pm.o
obj-$(CONFIG_GENERIC_MSI_IRQ) += msi.o
obj-$(CONFIG_GENERIC_IRQ_IPI) += ipi.o
+obj-$(CONFIG_SMP) += affinity.o
diff --git a/kernel/irq/affinity.c b/kernel/irq/affinity.c
new file mode 100644
index 0000000..1daf8fb
--- /dev/null
+++ b/kernel/irq/affinity.c
@@ -0,0 +1,60 @@
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/cpu.h>
+
+static int get_first_sibling(unsigned int cpu)
+{
+ unsigned int ret;
+
+ ret = cpumask_first(topology_sibling_cpumask(cpu));
+ if (ret < nr_cpu_ids)
+ return ret;
+ return cpu;
+}
+
+/*
+ * Take a map of online CPUs and the number of available interrupt vectors
+ * and generate an output cpumask suitable for spreading MSI/MSI-X vectors
+ * so that they are distributed as good as possible around the CPUs. If
+ * more vectors than CPUs are available we'll map one to each CPU,
+ * otherwise we map one to the first sibling of each socket.
+ *
+ * If there are more vectors than CPUs we will still only have one bit
+ * set per CPU, but interrupt code will keep on assining the vectors from
+ * the start of the bitmap until we run out of vectors.
+ */
+int irq_create_affinity_mask(struct cpumask **affinity_mask,
+ unsigned int *nr_vecs)
+{
+ unsigned int vecs = 0;
+
+ if (*nr_vecs == 1) {
+ *affinity_mask = NULL;
+ return 0;
+ }
+
+ *affinity_mask = kzalloc(cpumask_size(), GFP_KERNEL);
+ if (!*affinity_mask)
+ return -ENOMEM;
+
+ if (*nr_vecs >= num_online_cpus()) {
+ cpumask_copy(*affinity_mask, cpu_online_mask);
+ } else {
+ unsigned int cpu;
+
+ for_each_online_cpu(cpu) {
+ if (cpu == get_first_sibling(cpu)) {
+ cpumask_set_cpu(cpu, *affinity_mask);
+ vecs++;
+ }
+
+ if (--(*nr_vecs) == 0)
+ break;
+ }
+ }
+
+ *nr_vecs = vecs;
+ return 0;
+}
--
2.1.4
[toc] | [prev] | [next] | [standalone]
| From | "Guilherme G. Piccoli" <gpiccoli@linux.vnet.ibm.com> |
|---|---|
| Date | 2016-06-15 00:00 +0200 |
| Subject | Re: [PATCH 06/13] irq: add a helper spread an affinity mask for MSI/MSI-X vectors |
| Message-ID | <rK4xp-23y-21@gated-at.bofh.it> |
| In reply to | #1422266 |
On 06/14/2016 04:58 PM, Christoph Hellwig wrote:
> This is lifted from the blk-mq code and adopted to use the affinity mask
> concept just intruced in the irq handling code.
Very nice patch Christoph, thanks. There's a little typo above, on
"intruced".
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
> include/linux/interrupt.h | 11 +++++++++
> kernel/irq/Makefile | 1 +
> kernel/irq/affinity.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 72 insertions(+)
> create mode 100644 kernel/irq/affinity.c
>
> diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
> index 9fcabeb..12003c0 100644
> --- a/include/linux/interrupt.h
> +++ b/include/linux/interrupt.h
> @@ -278,6 +278,9 @@ extern int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m);
> extern int
> irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify);
>
> +int irq_create_affinity_mask(struct cpumask **affinity_mask,
> + unsigned int *nr_vecs);
> +
> #else /* CONFIG_SMP */
>
> static inline int irq_set_affinity(unsigned int irq, const struct cpumask *m)
> @@ -308,6 +311,14 @@ irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify)
> {
> return 0;
> }
> +
> +static inline int irq_create_affinity_mask(struct cpumask **affinity_mask,
> + unsigned int *nr_vecs)
> +{
> + *affinity_mask = NULL;
> + *nr_vecs = 1;
> + return 0;
> +}
> #endif /* CONFIG_SMP */
>
> /*
> diff --git a/kernel/irq/Makefile b/kernel/irq/Makefile
> index 2ee42e9..1d3ee31 100644
> --- a/kernel/irq/Makefile
> +++ b/kernel/irq/Makefile
> @@ -9,3 +9,4 @@ obj-$(CONFIG_GENERIC_IRQ_MIGRATION) += cpuhotplug.o
> obj-$(CONFIG_PM_SLEEP) += pm.o
> obj-$(CONFIG_GENERIC_MSI_IRQ) += msi.o
> obj-$(CONFIG_GENERIC_IRQ_IPI) += ipi.o
> +obj-$(CONFIG_SMP) += affinity.o
> diff --git a/kernel/irq/affinity.c b/kernel/irq/affinity.c
> new file mode 100644
> index 0000000..1daf8fb
> --- /dev/null
> +++ b/kernel/irq/affinity.c
> @@ -0,0 +1,60 @@
> +
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +#include <linux/cpu.h>
> +
> +static int get_first_sibling(unsigned int cpu)
> +{
> + unsigned int ret;
> +
> + ret = cpumask_first(topology_sibling_cpumask(cpu));
> + if (ret < nr_cpu_ids)
> + return ret;
> + return cpu;
> +}
> +
> +/*
> + * Take a map of online CPUs and the number of available interrupt vectors
> + * and generate an output cpumask suitable for spreading MSI/MSI-X vectors
> + * so that they are distributed as good as possible around the CPUs. If
> + * more vectors than CPUs are available we'll map one to each CPU,
> + * otherwise we map one to the first sibling of each socket.
> + *
> + * If there are more vectors than CPUs we will still only have one bit
> + * set per CPU, but interrupt code will keep on assining the vectors from
> + * the start of the bitmap until we run out of vectors.
> + */
Another little typo above in "assining".
I take this opportunity to ask you something, since I'm working in a
related code in a specific driver - sorry in advance if my question is
silly or if I misunderstood your code.
The function irq_create_affinity_mask() below deals with the case in
which we have nr_vecs < num_online_cpus(); in this case, wouldn't be a
good idea to trying distribute the vecs among cores?
Example: if we have 128 online cpus, 8 per core (meaning 16 cores) and
64 vecs, I guess would be ideal to distribute 4 vecs _per core_, leaving
4 CPUs in each core without vecs.
Makes sense for you?
Thanks,
Guilherme
> +int irq_create_affinity_mask(struct cpumask **affinity_mask,
> + unsigned int *nr_vecs)
> +{
> + unsigned int vecs = 0;
> +
> + if (*nr_vecs == 1) {
> + *affinity_mask = NULL;
> + return 0;
> + }
> +
> + *affinity_mask = kzalloc(cpumask_size(), GFP_KERNEL);
> + if (!*affinity_mask)
> + return -ENOMEM;
> +
> + if (*nr_vecs >= num_online_cpus()) {
> + cpumask_copy(*affinity_mask, cpu_online_mask);
> + } else {
> + unsigned int cpu;
> +
> + for_each_online_cpu(cpu) {
> + if (cpu == get_first_sibling(cpu)) {
> + cpumask_set_cpu(cpu, *affinity_mask);
> + vecs++;
> + }
> +
> + if (--(*nr_vecs) == 0)
> + break;
> + }
> + }
> +
> + *nr_vecs = vecs;
> + return 0;
> +}
>
[toc] | [prev] | [next] | [standalone]
| From | Christoph Hellwig <hch@lst.de> |
|---|---|
| Date | 2016-06-15 12:20 +0200 |
| Subject | Re: [PATCH 06/13] irq: add a helper spread an affinity mask for MSI/MSI-X vectors |
| Message-ID | <rKg5r-1fI-17@gated-at.bofh.it> |
| In reply to | #1422371 |
On Tue, Jun 14, 2016 at 06:54:22PM -0300, Guilherme G. Piccoli wrote: > On 06/14/2016 04:58 PM, Christoph Hellwig wrote: >> This is lifted from the blk-mq code and adopted to use the affinity mask >> concept just intruced in the irq handling code. > > Very nice patch Christoph, thanks. There's a little typo above, on > "intruced". fixed. > Another little typo above in "assining". fixed a swell. > I take this opportunity to ask you something, since I'm working in a > related code in a specific driver Which driver? One of the points here is to get this sort of code out of drivers and into common code.. > - sorry in advance if my question is > silly or if I misunderstood your code. > > The function irq_create_affinity_mask() below deals with the case in which > we have nr_vecs < num_online_cpus(); in this case, wouldn't be a good idea > to trying distribute the vecs among cores? > > Example: if we have 128 online cpus, 8 per core (meaning 16 cores) and 64 > vecs, I guess would be ideal to distribute 4 vecs _per core_, leaving 4 > CPUs in each core without vecs. There have been some reports about the blk-mq IRQ distribution being suboptimal, but no one sent patches so far. This patch just moves the existing algorithm into the core code to be better bisectable. I think an algorithm that takes cores into account instead of just SMT sibling would be very useful. So if you have a case where this helps for you an incremental patch (or even one against the current blk-mq code for now) would be appreciated.
[toc] | [prev] | [next] | [standalone]
| From | "Guilherme G. Piccoli" <gpiccoli@linux.vnet.ibm.com> |
|---|---|
| Date | 2016-06-15 15:10 +0200 |
| Subject | Re: [PATCH 06/13] irq: add a helper spread an affinity mask for MSI/MSI-X vectors |
| Message-ID | <rKiJY-2Ya-33@gated-at.bofh.it> |
| In reply to | #1422866 |
Thanks for the responses Bart and Christoph. On 06/15/2016 07:10 AM, Christoph Hellwig wrote: > On Tue, Jun 14, 2016 at 06:54:22PM -0300, Guilherme G. Piccoli wrote: >> On 06/14/2016 04:58 PM, Christoph Hellwig wrote: >>> This is lifted from the blk-mq code and adopted to use the affinity mask >>> concept just intruced in the irq handling code. >> >> Very nice patch Christoph, thanks. There's a little typo above, on >> "intruced". > > fixed. > >> Another little typo above in "assining". > > fixed a swell. > >> I take this opportunity to ask you something, since I'm working in a >> related code in a specific driver > > Which driver? One of the points here is to get this sort of code out > of drivers and into common code.. A network driver, i40e. I'd be glad to implement/see some common code to raise the topology information I need, but I was implementing on i40e more as a test case/toy example heheh... >> - sorry in advance if my question is >> silly or if I misunderstood your code. >> >> The function irq_create_affinity_mask() below deals with the case in which >> we have nr_vecs < num_online_cpus(); in this case, wouldn't be a good idea >> to trying distribute the vecs among cores? >> >> Example: if we have 128 online cpus, 8 per core (meaning 16 cores) and 64 >> vecs, I guess would be ideal to distribute 4 vecs _per core_, leaving 4 >> CPUs in each core without vecs. > > There have been some reports about the blk-mq IRQ distribution being > suboptimal, but no one sent patches so far. This patch just moves the > existing algorithm into the core code to be better bisectable. > > I think an algorithm that takes cores into account instead of just SMT > sibling would be very useful. So if you have a case where this helps > for you an incremental patch (or even one against the current blk-mq > code for now) would be appreciated. ...but now I'll focus on the common/general case! Thanks for the suggestion Christoph. I guess would be even better to have a generic function that retrieves an optimal mask, something like topology_get_optimal_mask(n, *cpumask), in which we get the best distribution of n CPUs among all cores and return such a mask - interesting case is when n < num_online_cpus. So, this function could be used inside your irq_create_affinity_mask() and maybe in other places it is needed. I was planning to use topology_core_id() to retrieve the core of a CPU, if anybody has a better idea, I'd be glad to hear it. Cheers, Guilherme > > _______________________________________________ > Linux-nvme mailing list > Linux-nvme@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-nvme >
[toc] | [prev] | [next] | [standalone]
| From | Christoph Hellwig <hch@lst.de> |
|---|---|
| Date | 2016-06-16 17:20 +0200 |
| Subject | Re: [PATCH 06/13] irq: add a helper spread an affinity mask for MSI/MSI-X vectors |
| Message-ID | <rKHfk-1xv-17@gated-at.bofh.it> |
| In reply to | #1423001 |
> > ...but now I'll focus on the common/general case! Thanks for the suggestion > Christoph. I guess would be even better to have a generic function that > retrieves an optimal mask, something like topology_get_optimal_mask(n, > *cpumask), in which we get the best distribution of n CPUs among all cores > and return such a mask - interesting case is when n < num_online_cpus. So, > this function could be used inside your irq_create_affinity_mask() and > maybe in other places it is needed. Yes, we should probably just plug this in where we're using the current routines. Block very much optimizes for the cases of either 1 queue or enough queues for all cpus at the moments. It would be good to check what the network drivers currently do.
[toc] | [prev] | [next] | [standalone]
| From | Christoph Hellwig <hch@lst.de> |
|---|---|
| Date | 2016-06-14 22:00 +0200 |
| Subject | [PATCH 07/13] pci: Provide sensible irq vector alloc/free routines |
| Message-ID | <rK2Fc-Rz-23@gated-at.bofh.it> |
| In reply to | #1422263 |
Add a helper to allocate a range of interrupt vectors, which will
transparently use MSI-X and MSI if available or fallback to legacy
vectors. The interrupts are available in a core managed array
in the pci_dev structure, and can also be released using a similar
helper.
The next patch will also add automatic spreading of MSI / MSI-X
vectors to this function.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/pci/msi.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/pci.h | 18 +++++++++
2 files changed, 128 insertions(+)
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index a080f44..a33adec 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -4,6 +4,7 @@
*
* Copyright (C) 2003-2004 Intel
* Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
+ * Copyright (c) 2016 Christoph Hellwig.
*/
#include <linux/err.h>
@@ -1120,6 +1121,115 @@ int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
}
EXPORT_SYMBOL(pci_enable_msix_range);
+static unsigned int pci_nr_irq_vectors(struct pci_dev *pdev)
+{
+ int nr_entries;
+
+ nr_entries = pci_msix_vec_count(pdev);
+ if (nr_entries <= 0 && pci_msi_supported(pdev, 1))
+ nr_entries = pci_msi_vec_count(pdev);
+ if (nr_entries <= 0)
+ nr_entries = 1;
+ return nr_entries;
+}
+
+static int pci_enable_msix_range_wrapper(struct pci_dev *pdev, u32 *irqs,
+ unsigned int min_vecs, unsigned int max_vecs)
+{
+ struct msix_entry *msix_entries;
+ int vecs, i;
+
+ msix_entries = kcalloc(max_vecs, sizeof(struct msix_entry), GFP_KERNEL);
+ if (!msix_entries)
+ return -ENOMEM;
+
+ for (i = 0; i < max_vecs; i++)
+ msix_entries[i].entry = i;
+
+ vecs = pci_enable_msix_range(pdev, msix_entries, min_vecs, max_vecs);
+ if (vecs > 0) {
+ for (i = 0; i < vecs; i++)
+ irqs[i] = msix_entries[i].vector;
+ }
+
+ kfree(msix_entries);
+ return vecs;
+}
+
+/**
+ * pci_alloc_irq_vectors - allocate multiple IRQs for a device
+ * @dev: PCI device to operate on
+ * @min_vecs: minimum number of vectors required (must be >= 1)
+ * @max_vecs: maximum (desired) number of vectors
+ * @flags: flags or quirks for the allocation
+ *
+ * Allocate up to @max_vecs interrupt vectors for @dev, using MSI-X or MSI
+ * vectors if available, and fall back to a single legacy vector
+ * if neither is available. Return the number of vectors allocated,
+ * (which might be smaller than @max_vecs) if successful, or a negative
+ * error code on error. The Linux irq numbers for the allocated
+ * vectors are stored in pdev->irqs. If less than @min_vecs interrupt
+ * vectors are available for @dev the function will fail with -ENOSPC.
+ */
+int pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs,
+ unsigned int max_vecs, unsigned int flags)
+{
+ unsigned int vecs, i;
+ u32 *irqs;
+
+ max_vecs = min(max_vecs, pci_nr_irq_vectors(dev));
+
+ irqs = kcalloc(max_vecs, sizeof(u32), GFP_KERNEL);
+ if (!irqs)
+ return -ENOMEM;
+
+ if (!(flags & PCI_IRQ_NOMSIX)) {
+ vecs = pci_enable_msix_range_wrapper(dev, irqs, min_vecs,
+ max_vecs);
+ if (vecs > 0)
+ goto done;
+ }
+
+ vecs = pci_enable_msi_range(dev, min_vecs, max_vecs);
+ if (vecs > 0) {
+ for (i = 0; i < vecs; i++)
+ irqs[i] = dev->irq + i;
+ goto done;
+ }
+
+ if (min_vecs > 1)
+ return -ENOSPC;
+
+ /* use legacy irq */
+ kfree(irqs);
+ dev->irqs = &dev->irq;
+ return 1;
+
+done:
+ dev->irqs = irqs;
+ return vecs;
+}
+EXPORT_SYMBOL(pci_alloc_irq_vectors);
+
+/**
+ * pci_free_irq_vectors - free previously allocated IRQs for a device
+ * @dev: PCI device to operate on
+ *
+ * Undoes the allocations and enabling in pci_alloc_irq_vectors().
+ */
+void pci_free_irq_vectors(struct pci_dev *dev)
+{
+ if (dev->msix_enabled)
+ pci_disable_msix(dev);
+ else if (dev->msi_enabled)
+ pci_disable_msi(dev);
+
+ if (dev->irqs != &dev->irq)
+ kfree(dev->irqs);
+}
+EXPORT_SYMBOL(pci_free_irq_vectors);
+
+
struct pci_dev *msi_desc_to_pci_dev(struct msi_desc *desc)
{
return to_pci_dev(desc->dev);
diff --git a/include/linux/pci.h b/include/linux/pci.h
index b67e4df..84a20fc 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -320,6 +320,7 @@ struct pci_dev {
* directly, use the values stored here. They might be different!
*/
unsigned int irq;
+ unsigned int *irqs;
struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */
bool match_driver; /* Skip attaching driver */
@@ -1237,6 +1238,8 @@ resource_size_t pcibios_iov_resource_alignment(struct pci_dev *dev, int resno);
int pci_set_vga_state(struct pci_dev *pdev, bool decode,
unsigned int command_bits, u32 flags);
+#define PCI_IRQ_NOMSIX (1 << 0) /* don't try to use MSI-X interrupts */
+
/* kmem_cache style wrapper around pci_alloc_consistent() */
#include <linux/pci-dma.h>
@@ -1284,6 +1287,9 @@ static inline int pci_enable_msix_exact(struct pci_dev *dev,
return rc;
return 0;
}
+int pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs,
+ unsigned int max_vecs, unsigned int flags);
+void pci_free_irq_vectors(struct pci_dev *dev);
#else
static inline int pci_msi_vec_count(struct pci_dev *dev) { return -ENOSYS; }
static inline void pci_msi_shutdown(struct pci_dev *dev) { }
@@ -1307,6 +1313,18 @@ static inline int pci_enable_msix_range(struct pci_dev *dev,
static inline int pci_enable_msix_exact(struct pci_dev *dev,
struct msix_entry *entries, int nvec)
{ return -ENOSYS; }
+static inline int pci_alloc_irq_vectors(struct pci_dev *dev,
+ unsigned int min_vecs, unsigned int max_vecs,
+ unsigned int flags)
+{
+ if (min_vecs > 1)
+ return -ENOSPC;
+ dev->irqs = &dev->irq;
+ return 1;
+}
+static inline void pci_free_irq_vectors(struct pci_dev *dev)
+{
+}
#endif
#ifdef CONFIG_PCIEPORTBUS
--
2.1.4
[toc] | [prev] | [next] | [standalone]
| From | Alexander Gordeev <agordeev@redhat.com> |
|---|---|
| Date | 2016-06-23 13:20 +0200 |
| Subject | Re: [PATCH 07/13] pci: Provide sensible irq vector alloc/free routines |
| Message-ID | <rNaPU-IX-11@gated-at.bofh.it> |
| In reply to | #1422267 |
On Tue, Jun 14, 2016 at 09:59:00PM +0200, Christoph Hellwig wrote:
> Add a helper to allocate a range of interrupt vectors, which will
> transparently use MSI-X and MSI if available or fallback to legacy
> vectors. The interrupts are available in a core managed array
> in the pci_dev structure, and can also be released using a similar
> helper.
>
> The next patch will also add automatic spreading of MSI / MSI-X
> vectors to this function.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
> drivers/pci/msi.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> include/linux/pci.h | 18 +++++++++
New APIs should be documented in Documentation/PCI/MSI-HOWTO.txt, I guess.
> 2 files changed, 128 insertions(+)
>
> diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
> index a080f44..a33adec 100644
> --- a/drivers/pci/msi.c
> +++ b/drivers/pci/msi.c
> @@ -4,6 +4,7 @@
> *
> * Copyright (C) 2003-2004 Intel
> * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
> + * Copyright (c) 2016 Christoph Hellwig.
> */
>
> #include <linux/err.h>
> @@ -1120,6 +1121,115 @@ int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
> }
> EXPORT_SYMBOL(pci_enable_msix_range);
>
> +static unsigned int pci_nr_irq_vectors(struct pci_dev *pdev)
> +{
> + int nr_entries;
> +
> + nr_entries = pci_msix_vec_count(pdev);
> + if (nr_entries <= 0 && pci_msi_supported(pdev, 1))
> + nr_entries = pci_msi_vec_count(pdev);
> + if (nr_entries <= 0)
> + nr_entries = 1;
> + return nr_entries;
> +}
This function is strange, because it:
(a) does not consider PCI_IRQ_NOMSIX flag;
(b) only calls pci_msi_supported() for MSI case;
(c) calls pci_msi_supported() with just one vector;
(d) might return suboptimal number of vectors (number of MSI-X used
later for MSI or vice versa)
Overall, I would suggest simply return maximum between MSI-X and MSI
numbers and let the rest of the code (i.e the two range functions)
handle a-d.
> +static int pci_enable_msix_range_wrapper(struct pci_dev *pdev, u32 *irqs,
> + unsigned int min_vecs, unsigned int max_vecs)
> +{
> + struct msix_entry *msix_entries;
> + int vecs, i;
> +
> + msix_entries = kcalloc(max_vecs, sizeof(struct msix_entry), GFP_KERNEL);
> + if (!msix_entries)
> + return -ENOMEM;
> +
> + for (i = 0; i < max_vecs; i++)
> + msix_entries[i].entry = i;
> +
> + vecs = pci_enable_msix_range(pdev, msix_entries, min_vecs, max_vecs);
> + if (vecs > 0) {
This condition check is unneeded.
> + for (i = 0; i < vecs; i++)
> + irqs[i] = msix_entries[i].vector;
> + }
> +
> + kfree(msix_entries);
> + return vecs;
> +}
> +
> +/**
> + * pci_alloc_irq_vectors - allocate multiple IRQs for a device
> + * @dev: PCI device to operate on
> + * @min_vecs: minimum number of vectors required (must be >= 1)
> + * @max_vecs: maximum (desired) number of vectors
> + * @flags: flags or quirks for the allocation
> + *
> + * Allocate up to @max_vecs interrupt vectors for @dev, using MSI-X or MSI
> + * vectors if available, and fall back to a single legacy vector
> + * if neither is available. Return the number of vectors allocated,
> + * (which might be smaller than @max_vecs) if successful, or a negative
> + * error code on error. The Linux irq numbers for the allocated
> + * vectors are stored in pdev->irqs. If less than @min_vecs interrupt
> + * vectors are available for @dev the function will fail with -ENOSPC.
> + */
> +int pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs,
> + unsigned int max_vecs, unsigned int flags)
> +{
> + unsigned int vecs, i;
> + u32 *irqs;
> +
> + max_vecs = min(max_vecs, pci_nr_irq_vectors(dev));
Optionally, you could move this assignment to pci_nr_irq_vectors() and
simply let it handle number of vectors to request.
> + irqs = kcalloc(max_vecs, sizeof(u32), GFP_KERNEL);
> + if (!irqs)
> + return -ENOMEM;
> +
> + if (!(flags & PCI_IRQ_NOMSIX)) {
> + vecs = pci_enable_msix_range_wrapper(dev, irqs, min_vecs,
> + max_vecs);
> + if (vecs > 0)
> + goto done;
> + }
> +
> + vecs = pci_enable_msi_range(dev, min_vecs, max_vecs);
> + if (vecs > 0) {
> + for (i = 0; i < vecs; i++)
> + irqs[i] = dev->irq + i;
> + goto done;
> + }
> +
> + if (min_vecs > 1)
> + return -ENOSPC;
irqs is leaked if (min_vecs > 1)
You can get rid of this check at all if you reorganize your code i.e.
like this:
...
vecs = pci_enable_msi_range(dev, min_vecs, max_vecs);
if (vecs < 0)
goto legacy;
for (i = 0; i < vecs; i++)
irqs[i] = dev->irq + i;
done:
...
legacy:
...
> +
> + /* use legacy irq */
> + kfree(irqs);
> + dev->irqs = &dev->irq;
> + return 1;
> +
> +done:
> + dev->irqs = irqs;
> + return vecs;
> +}
> +EXPORT_SYMBOL(pci_alloc_irq_vectors);
> +
> +/**
> + * pci_free_irq_vectors - free previously allocated IRQs for a device
> + * @dev: PCI device to operate on
> + *
> + * Undoes the allocations and enabling in pci_alloc_irq_vectors().
> + */
> +void pci_free_irq_vectors(struct pci_dev *dev)
> +{
> + if (dev->msix_enabled)
> + pci_disable_msix(dev);
> + else if (dev->msi_enabled)
> + pci_disable_msi(dev);
The checks are probably redundant or incomplete. Redundant - because
pci_disable_msi()/pci_disable_msix() do it anyways:
if (!pci_msi_enable || !dev || !dev->msi_enabled)
return;
Incomplete - because the two other conditions are not checked.
> + if (dev->irqs != &dev->irq)
> + kfree(dev->irqs);
Unset dev->irqs?
BTW, since (dev->irqs == &dev->irq) effectively checks if MSI/MSI-X
was enabled this function could bail out in case they did not.
> +}
> +EXPORT_SYMBOL(pci_free_irq_vectors);
> +
> +
> struct pci_dev *msi_desc_to_pci_dev(struct msi_desc *desc)
> {
> return to_pci_dev(desc->dev);
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index b67e4df..84a20fc 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -320,6 +320,7 @@ struct pci_dev {
> * directly, use the values stored here. They might be different!
> */
> unsigned int irq;
> + unsigned int *irqs;
> struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */
>
> bool match_driver; /* Skip attaching driver */
> @@ -1237,6 +1238,8 @@ resource_size_t pcibios_iov_resource_alignment(struct pci_dev *dev, int resno);
> int pci_set_vga_state(struct pci_dev *pdev, bool decode,
> unsigned int command_bits, u32 flags);
>
> +#define PCI_IRQ_NOMSIX (1 << 0) /* don't try to use MSI-X interrupts */
BTW, why PCI_IRQ_NOMSIX only and no PCI_IRQ_NOMSI?
> /* kmem_cache style wrapper around pci_alloc_consistent() */
>
> #include <linux/pci-dma.h>
> @@ -1284,6 +1287,9 @@ static inline int pci_enable_msix_exact(struct pci_dev *dev,
> return rc;
> return 0;
> }
> +int pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs,
> + unsigned int max_vecs, unsigned int flags);
> +void pci_free_irq_vectors(struct pci_dev *dev);
> #else
> static inline int pci_msi_vec_count(struct pci_dev *dev) { return -ENOSYS; }
> static inline void pci_msi_shutdown(struct pci_dev *dev) { }
> @@ -1307,6 +1313,18 @@ static inline int pci_enable_msix_range(struct pci_dev *dev,
> static inline int pci_enable_msix_exact(struct pci_dev *dev,
> struct msix_entry *entries, int nvec)
> { return -ENOSYS; }
> +static inline int pci_alloc_irq_vectors(struct pci_dev *dev,
> + unsigned int min_vecs, unsigned int max_vecs,
> + unsigned int flags)
> +{
> + if (min_vecs > 1)
> + return -ENOSPC;
> + dev->irqs = &dev->irq;
> + return 1;
> +}
> +static inline void pci_free_irq_vectors(struct pci_dev *dev)
> +{
Unset dev->irqs?
> +}
> #endif
>
> #ifdef CONFIG_PCIEPORTBUS
> --
> 2.1.4
>
[toc] | [prev] | [next] | [standalone]
| From | Christoph Hellwig <hch@lst.de> |
|---|---|
| Date | 2016-06-14 22:00 +0200 |
| Subject | [PATCH 02/13] irq: Introduce IRQD_AFFINITY_MANAGED flag |
| Message-ID | <rK2Fc-Rz-13@gated-at.bofh.it> |
| In reply to | #1422263 |
From: Thomas Gleixner <tglx@linutronix.de>
Interupts marked with this flag are excluded from user space interrupt
affinity changes. Contrary to the IRQ_NO_BALANCING flag, the kernel internal
affinity mechanism is not blocked.
This flag will be used for multi-queue device interrupts.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
include/linux/irq.h | 7 +++++++
kernel/irq/internals.h | 2 ++
kernel/irq/manage.c | 21 ++++++++++++++++++---
kernel/irq/proc.c | 2 +-
4 files changed, 28 insertions(+), 4 deletions(-)
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 4d758a7..49d66d1 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -197,6 +197,7 @@ struct irq_data {
* IRQD_IRQ_INPROGRESS - In progress state of the interrupt
* IRQD_WAKEUP_ARMED - Wakeup mode armed
* IRQD_FORWARDED_TO_VCPU - The interrupt is forwarded to a VCPU
+ * IRQD_AFFINITY_MANAGED - Affinity is managed automatically
*/
enum {
IRQD_TRIGGER_MASK = 0xf,
@@ -212,6 +213,7 @@ enum {
IRQD_IRQ_INPROGRESS = (1 << 18),
IRQD_WAKEUP_ARMED = (1 << 19),
IRQD_FORWARDED_TO_VCPU = (1 << 20),
+ IRQD_AFFINITY_MANAGED = (1 << 21),
};
#define __irqd_to_state(d) ACCESS_PRIVATE((d)->common, state_use_accessors)
@@ -305,6 +307,11 @@ static inline void irqd_clr_forwarded_to_vcpu(struct irq_data *d)
__irqd_to_state(d) &= ~IRQD_FORWARDED_TO_VCPU;
}
+static inline bool irqd_affinity_is_managed(struct irq_data *d)
+{
+ return __irqd_to_state(d) & IRQD_AFFINITY_MANAGED;
+}
+
#undef __irqd_to_state
static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h
index 09be2c9..b15aa3b 100644
--- a/kernel/irq/internals.h
+++ b/kernel/irq/internals.h
@@ -105,6 +105,8 @@ static inline void unregister_handler_proc(unsigned int irq,
struct irqaction *action) { }
#endif
+extern bool irq_can_set_affinity_usr(unsigned int irq);
+
extern int irq_select_affinity_usr(unsigned int irq, struct cpumask *mask);
extern void irq_set_thread_affinity(struct irq_desc *desc);
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index ef0bc02..30658e9 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -115,12 +115,12 @@ EXPORT_SYMBOL(synchronize_irq);
#ifdef CONFIG_SMP
cpumask_var_t irq_default_affinity;
-static int __irq_can_set_affinity(struct irq_desc *desc)
+static bool __irq_can_set_affinity(struct irq_desc *desc)
{
if (!desc || !irqd_can_balance(&desc->irq_data) ||
!desc->irq_data.chip || !desc->irq_data.chip->irq_set_affinity)
- return 0;
- return 1;
+ return false;
+ return true;
}
/**
@@ -134,6 +134,21 @@ int irq_can_set_affinity(unsigned int irq)
}
/**
+ * irq_can_set_affinity_usr - Check if affinity of a irq can be set from user space
+ * @irq: Interrupt to check
+ *
+ * Like irq_can_set_affinity() above, but additionally checks for the
+ * AFFINITY_MANAGED flag.
+ */
+bool irq_can_set_affinity_usr(unsigned int irq)
+{
+ struct irq_desc *desc = irq_to_desc(irq);
+
+ return __irq_can_set_affinity(desc) &&
+ !irqd_affinity_is_managed(&desc->irq_data);
+}
+
+/**
* irq_set_thread_affinity - Notify irq threads to adjust affinity
* @desc: irq descriptor which has affitnity changed
*
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
index 4e1b947..40bdcdc 100644
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -96,7 +96,7 @@ static ssize_t write_irq_affinity(int type, struct file *file,
cpumask_var_t new_value;
int err;
- if (!irq_can_set_affinity(irq) || no_irq_affinity)
+ if (!irq_can_set_affinity_usr(irq) || no_irq_affinity)
return -EIO;
if (!alloc_cpumask_var(&new_value, GFP_KERNEL))
--
2.1.4
[toc] | [prev] | [next] | [standalone]
| From | Christoph Hellwig <hch@lst.de> |
|---|---|
| Date | 2016-06-15 12:30 +0200 |
| Subject | Re: [PATCH 02/13] irq: Introduce IRQD_AFFINITY_MANAGED flag |
| Message-ID | <rKgfd-1jj-5@gated-at.bofh.it> |
| In reply to | #1422268 |
Hi Bart, On Wed, Jun 15, 2016 at 10:44:37AM +0200, Bart Van Assche wrote: > However, is excluding these interrupts from irqbalanced really the > way to go? What positive effect will irqbalanced have on explcititly spread interrupts? > Suppose e.g. that a system is equipped with two RDMA adapters, > that these adapters are used by a blk-mq enabled block initiator driver and > that each adapter supports eight MSI-X vectors. Should the interrupts of > the two RDMA adapters be assigned to different CPU cores? If so, which > software layer should realize this? The kernel or user space? RDMA should eventually use the interrupt spreading implemented in this series, as should networking (RDMA actually is on my near term todo list). RDMA block protocols will then pick up the queue information from the HCA driver. I've not actually implemented this yet, but my current idea is: - the HCA drivers are switch to use pci_alloc_irq_vectors to spread their interrupt vectors around the system - the HCA drivers will expose the irq_affinity affinity array in struct ib_device (we'll need to consider what do about the odd completion vectors instead of irq terminology in the RDMA stack, but that's not a show stopper) - multiqueue aware block drivers will then feed the irq_affinity cpumask from the hca driver to blk-mq. We'll also need to ensure the number of protocol queues aligns nicely to the number of hardware queues. My current thinking is that they should be the same or a fraction of the hardware completion queues, but this might need some careful benchmarking.
[toc] | [prev] | [next] | [standalone]
| From | Keith Busch <keith.busch@intel.com> |
|---|---|
| Date | 2016-06-15 17:10 +0200 |
| Subject | Re: [PATCH 02/13] irq: Introduce IRQD_AFFINITY_MANAGED flag |
| Message-ID | <rKkC6-4aQ-15@gated-at.bofh.it> |
| In reply to | #1422878 |
On Wed, Jun 15, 2016 at 12:42:53PM +0200, Bart Van Assche wrote: > Today irqbalanced is responsible for deciding how to assign interrupts from > different adapters to CPU cores. Does the above mean that for adapters that > support multiple MSI-X interrupts the kernel will have full responsibility > for assigning interrupt vectors to CPU cores? Hi Bart, Right, the kernel would be responsible for assigning interrupt vectors to cores. The kernel is already responsible for setting the affinity hint, but we want direct control because we can do a better than irqbalance, which has been a problem point for users. Many adapters gain significant performance when irqbalance is using "exact" hint policy. But that's not irqbalance's default setting, and we don't necessarily want to enforce "exact" on the entire system when only a subset of devices benefit from such a setup. > If two identical adapters are present in a system, will these generate the > same irq_affinity mask? Do you agree that interrupt vectors from different > adapters should be assigned to different CPU cores if enough CPU cores are > available? If so, which software layer will assign interrupt vectors from > different adapters to different CPU cores? I think the idea is have the irq_affinity mask match the CPU mapping on the submission side context associated with that particular vector. If two identical adapters generate the same submission CPU mapping, I don't think we can do better than matching irq_affinity masks. Thanks, Keith
[toc] | [prev] | [next] | [standalone]
| From | Keith Busch <keith.busch@intel.com> |
|---|---|
| Date | 2016-06-15 18:00 +0200 |
| Subject | Re: [PATCH 02/13] irq: Introduce IRQD_AFFINITY_MANAGED flag |
| Message-ID | <rKlou-4sY-13@gated-at.bofh.it> |
| In reply to | #1423122 |
On Wed, Jun 15, 2016 at 05:28:54PM +0200, Bart Van Assche wrote: > On 06/15/2016 05:14 PM, Keith Busch wrote: > >I think the idea is have the irq_affinity mask match the CPU mapping on > >the submission side context associated with that particular vector. If > >two identical adapters generate the same submission CPU mapping, I don't > >think we can do better than matching irq_affinity masks. > > Has this been verified by measurements? Sorry but I'm not convinced that > using the same mapping for multiple identical adapters instead of spreading > interrupts will result in better performance. The interrupts automatically spread based on which CPU submitted the work. If you want to spread interrupts across more CPUs, then you can spread submissions to the CPUs you want to service the interrupts. Completing work on the same CPU that submitted it is quickest with its cache hot access. I have equipment available to demo this. What affinty_mask policy would you like to see compared with the proposal?
[toc] | [prev] | [next] | [standalone]
| From | Keith Busch <keith.busch@intel.com> |
|---|---|
| Date | 2016-06-15 22:00 +0200 |
| Subject | Re: [PATCH 02/13] irq: Introduce IRQD_AFFINITY_MANAGED flag |
| Message-ID | <rKp8K-6LQ-15@gated-at.bofh.it> |
| In reply to | #1423180 |
On Wed, Jun 15, 2016 at 09:36:54PM +0200, Bart Van Assche wrote: > Sorry that I had not yet this made this clear but my concern is about a > system equipped with two or more adapters and with more CPU cores than the > number of MSI-X interrupts per adapter. Consider e.g. a system with two > adapters (A and B), 8 interrupts per adapter (A0..A7 and B0..B7), 32 CPU > cores and two NUMA nodes. Assuming that hyperthreading is disabled, will the > patches from this patch series generate the following interrupt assignment? > > 0: A0 B0 > 1: A1 B1 > 2: A2 B2 > 3: A3 B3 > 4: A4 B4 > 5: A5 B5 > 6: A6 B6 > 7: A7 B7 > 8: (none) > ... > 31: (none) I'll need to look at the follow on patches do to confirm, but that's not what this should do. All CPU's should have a vector assigned because every CPU needs to be assigned a submission context using a vector. In your example, every vector's affinity mask should be assigned to 4 CPUs: vector '8' starts over with A0 B0, '9' gets A1 B1, and so on. If it's done such that all CPUs are assigned and no sharing occurs across NUMA nodes, does that change your concern?
[toc] | [prev] | [next] | [standalone]
| From | Keith Busch <keith.busch@intel.com> |
|---|---|
| Date | 2016-06-15 22:10 +0200 |
| Subject | Re: [PATCH 02/13] irq: Introduce IRQD_AFFINITY_MANAGED flag |
| Message-ID | <rKpiq-74l-19@gated-at.bofh.it> |
| In reply to | #1423353 |
On Wed, Jun 15, 2016 at 04:06:55PM -0400, Keith Busch wrote: > > > > 0: A0 B0 > > 1: A1 B1 > > 2: A2 B2 > > 3: A3 B3 > > 4: A4 B4 > > 5: A5 B5 > > 6: A6 B6 > > 7: A7 B7 > > 8: (none) > > ... > > 31: (none) > > I'll need to look at the follow on patches do to confirm, but that's > not what this should do. All CPU's should have a vector assigned because > every CPU needs to be assigned a submission context using a vector. In > your example, every vector's affinity mask should be assigned to 4 CPUs: > vector '8' starts over with A0 B0, '9' gets A1 B1, and so on. ^^^^^^ Sorry, I meant "CPU '8'", not "vector '8'".
[toc] | [prev] | [next] | [standalone]
| From | Keith Busch <keith.busch@intel.com> |
|---|---|
| Date | 2016-06-16 17:20 +0200 |
| Subject | Re: [PATCH 02/13] irq: Introduce IRQD_AFFINITY_MANAGED flag |
| Message-ID | <rKHfk-1xv-25@gated-at.bofh.it> |
| In reply to | #1423362 |
On Wed, Jun 15, 2016 at 10:50:53PM +0200, Bart Van Assche wrote: > Does it matter on x86 systems whether or not these interrupt vectors are > also associated with a CPU with a higher CPU number? Although multiple bits > can be set in /proc/irq/<n>/smp_affinity only the first bit counts on x86 > platforms. In default_cpu_mask_to_apicid_and() it is easy to see that only > the first bit that has been set in that mask counts on x86 systems. Wow, thanks for the information. I didn't know the apic wasn't using the full cpu mask, so this changes how I need to look at this, and will experiment with such a configuration.
[toc] | [prev] | [next] | [standalone]
| From | Alexander Gordeev <agordeev@redhat.com> |
|---|---|
| Date | 2016-06-22 14:00 +0200 |
| Subject | Re: [PATCH 02/13] irq: Introduce IRQD_AFFINITY_MANAGED flag |
| Message-ID | <rMOZ3-2Tm-17@gated-at.bofh.it> |
| In reply to | #1424181 |
On Thu, Jun 16, 2016 at 11:19:51AM -0400, Keith Busch wrote: > On Wed, Jun 15, 2016 at 10:50:53PM +0200, Bart Van Assche wrote: > > Does it matter on x86 systems whether or not these interrupt vectors are > > also associated with a CPU with a higher CPU number? Although multiple bits > > can be set in /proc/irq/<n>/smp_affinity only the first bit counts on x86 > > platforms. In default_cpu_mask_to_apicid_and() it is easy to see that only > > the first bit that has been set in that mask counts on x86 systems. > > Wow, thanks for the information. I didn't know the apic wasn't using > the full cpu mask, so this changes how I need to look at this, and will > experiment with such a configuration. I have vague memories of this, but you probably need to check PPC as well. Its interrupt distribution is not straightforward as well, AFAIR.
[toc] | [prev] | [next] | [standalone]
| From | Christoph Hellwig <hch@lst.de> |
|---|---|
| Date | 2016-06-16 17:30 +0200 |
| Subject | Re: [PATCH 02/13] irq: Introduce IRQD_AFFINITY_MANAGED flag |
| Message-ID | <rKHp0-1Bu-25@gated-at.bofh.it> |
| In reply to | #1423180 |
On Wed, Jun 15, 2016 at 09:36:54PM +0200, Bart Van Assche wrote: > Do you agree that - ignoring other interrupt assignments - that the latter > interrupt assignment scheme would result in higher throughput and lower > interrupt processing latency? Probably. Once we've got it in the core IRQ code we can tweak the algorithm to be optimal.
[toc] | [prev] | [next] | [standalone]
| From | Christoph Hellwig <hch@lst.de> |
|---|---|
| Date | 2016-06-20 14:30 +0200 |
| Subject | Re: [PATCH 02/13] irq: Introduce IRQD_AFFINITY_MANAGED flag |
| Message-ID | <rM6v0-8aw-37@gated-at.bofh.it> |
| In reply to | #1424195 |
On Thu, Jun 16, 2016 at 05:39:07PM +0200, Bart Van Assche wrote: > On 06/16/2016 05:20 PM, Christoph Hellwig wrote: >> On Wed, Jun 15, 2016 at 09:36:54PM +0200, Bart Van Assche wrote: >>> Do you agree that - ignoring other interrupt assignments - that the latter >>> interrupt assignment scheme would result in higher throughput and lower >>> interrupt processing latency? >> >> Probably. Once we've got it in the core IRQ code we can tweak the >> algorithm to be optimal. > > Sorry but I'm afraid that we are embedding policy in the kernel, something > we should not do. I know that there are workloads for which dedicating some > CPU cores to interrupt processing and other CPU cores to running kernel > threads improves throughput, probably because this results in less cache > eviction on the CPU cores that run kernel threads and some degree of > interrupt coalescing on the CPU cores that process interrupts. And you can still easily set this use case up by chosing less queues (aka interrupts) than CPUs and assining your workload to the other cores. > My concern > is that I doubt that there is an interrupt assignment scheme that works > optimally for all workloads. Hence my request to preserve the ability to > modify interrupt affinity from user space. I'd say let's do such an interface incrementall based on the use case - especially after we get networking over to use common code to distribute the interrupts. If you were doing something like this with the current blk-mq code it wouldn't work very well due to the fact that you'd have a mismatch between the assigned interrupt and the blk-mq queue mapping anyway. It might be a good idea to start brainstorming how we'd want to handle this change - we'd basically need a per-device notification that the interrupt mapping changes so that we can rebuild the queue mapping, which is somewhat similar to the lib/cpu_rmap.c code used by a few networking drivers. This would also help with dealing with cpu hotplug events that change the cpu mapping.
[toc] | [prev] | [next] | [standalone]
Page 1 of 2 [1] 2 Next page →
Back to top | Article view | linux.kernel
csiph-web