Skip to content

Commit 55c5438

Browse files
Petr TesarikChristoph Hellwig
authored andcommitted
swiotlb: reduce area lock contention for non-primary IO TLB pools
If multiple areas and multiple IO TLB pools exist, first iterate the current CPU specific area in all pools. Then move to the next area index. This is best illustrated by a diagram: area 0 | area 1 | ... | area M | pool 0 A B C pool 1 D E ... pool N F G H Currently, each pool is searched before moving on to the next pool, i.e. the search order is A, B ... C, D, E ... F, G ... H. With this patch, each area is searched in all pools before moving on to the next area, i.e. the search order is A, D ... F, B, E ... G ... C ... H. Note that preemption is not disabled, and raw_smp_processor_id() may not return a stable result, but it is called only once to determine the initial area index. The search will iterate over all areas eventually, even if the current task is preempted. Next, some pools may have less (but not more) areas than default_nareas. Skip such pools if the distance from the initial area index is greater than pool->nareas. This logic ensures that for every pool the search starts in the initial CPU's own area and never tries any area twice. To verify performance impact, I booted the kernel with a minimum pool size ("swiotlb=512,4,force"), so multiple pools get allocated, and I ran these benchmarks: - small: single-threaded I/O of 4 KiB blocks, - big: single-threaded I/O of 64 KiB blocks, - 4way: 4-way parallel I/O of 4 KiB blocks. The "var" column in the tables below is the coefficient of variance over 5 runs of the test, the "diff" column is the relative difference against base in read-write I/O bandwidth (MiB/s). Tested on an x86 VM against a QEMU virtio SATA driver backed by a RAM-based block device on the host: base patched var var diff small 0.69% 0.62% +25.4% big 2.14% 2.27% +25.7% 4way 2.65% 1.70% +23.6% Tested on a Raspberry Pi against a class-10 A1 microSD card: base patched var var diff small 0.53% 1.96% -0.3% big 0.02% 0.57% +0.8% 4way 6.17% 0.40% +0.3% These results confirm that there is significant performance boost in the software IO TLB slot allocation itself. Where performance is dominated by actual hardware, there is no measurable change. Signed-off-by: Petr Tesarik <petr.tesarik1@huawei-partners.com> Reviewed-by: Mirsad Todorovac <mirsad.todorovac@alu.unizg.hr> Signed-off-by: Christoph Hellwig <hch@lst.de>
1 parent 4ad4c1f commit 55c5438

1 file changed

Lines changed: 55 additions & 35 deletions

File tree

kernel/dma/swiotlb.c

Lines changed: 55 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -957,7 +957,7 @@ static void dec_used(struct io_tlb_mem *mem, unsigned int nslots)
957957
#endif /* CONFIG_DEBUG_FS */
958958

959959
/**
960-
* swiotlb_area_find_slots() - search for slots in one IO TLB memory area
960+
* swiotlb_search_pool_area() - search one memory area in one pool
961961
* @dev: Device which maps the buffer.
962962
* @pool: Memory pool to be searched.
963963
* @area_index: Index of the IO TLB memory area to be searched.
@@ -972,7 +972,7 @@ static void dec_used(struct io_tlb_mem *mem, unsigned int nslots)
972972
*
973973
* Return: Index of the first allocated slot, or -1 on error.
974974
*/
975-
static int swiotlb_area_find_slots(struct device *dev, struct io_tlb_pool *pool,
975+
static int swiotlb_search_pool_area(struct device *dev, struct io_tlb_pool *pool,
976976
int area_index, phys_addr_t orig_addr, size_t alloc_size,
977977
unsigned int alloc_align_mask)
978978
{
@@ -1066,41 +1066,50 @@ static int swiotlb_area_find_slots(struct device *dev, struct io_tlb_pool *pool,
10661066
return slot_index;
10671067
}
10681068

1069+
#ifdef CONFIG_SWIOTLB_DYNAMIC
1070+
10691071
/**
1070-
* swiotlb_pool_find_slots() - search for slots in one memory pool
1072+
* swiotlb_search_area() - search one memory area in all pools
10711073
* @dev: Device which maps the buffer.
1072-
* @pool: Memory pool to be searched.
1074+
* @start_cpu: Start CPU number.
1075+
* @cpu_offset: Offset from @start_cpu.
10731076
* @orig_addr: Original (non-bounced) IO buffer address.
10741077
* @alloc_size: Total requested size of the bounce buffer,
10751078
* including initial alignment padding.
10761079
* @alloc_align_mask: Required alignment of the allocated buffer.
1080+
* @retpool: Used memory pool, updated on return.
10771081
*
1078-
* Search through one memory pool to find a sequence of slots that match the
1082+
* Search one memory area in all pools for a sequence of slots that match the
10791083
* allocation constraints.
10801084
*
10811085
* Return: Index of the first allocated slot, or -1 on error.
10821086
*/
1083-
static int swiotlb_pool_find_slots(struct device *dev, struct io_tlb_pool *pool,
1084-
phys_addr_t orig_addr, size_t alloc_size,
1085-
unsigned int alloc_align_mask)
1087+
static int swiotlb_search_area(struct device *dev, int start_cpu,
1088+
int cpu_offset, phys_addr_t orig_addr, size_t alloc_size,
1089+
unsigned int alloc_align_mask, struct io_tlb_pool **retpool)
10861090
{
1087-
int start = raw_smp_processor_id() & (pool->nareas - 1);
1088-
int i = start, index;
1089-
1090-
do {
1091-
index = swiotlb_area_find_slots(dev, pool, i, orig_addr,
1092-
alloc_size, alloc_align_mask);
1093-
if (index >= 0)
1094-
return index;
1095-
if (++i >= pool->nareas)
1096-
i = 0;
1097-
} while (i != start);
1091+
struct io_tlb_mem *mem = dev->dma_io_tlb_mem;
1092+
struct io_tlb_pool *pool;
1093+
int area_index;
1094+
int index = -1;
10981095

1099-
return -1;
1096+
rcu_read_lock();
1097+
list_for_each_entry_rcu(pool, &mem->pools, node) {
1098+
if (cpu_offset >= pool->nareas)
1099+
continue;
1100+
area_index = (start_cpu + cpu_offset) & (pool->nareas - 1);
1101+
index = swiotlb_search_pool_area(dev, pool, area_index,
1102+
orig_addr, alloc_size,
1103+
alloc_align_mask);
1104+
if (index >= 0) {
1105+
*retpool = pool;
1106+
break;
1107+
}
1108+
}
1109+
rcu_read_unlock();
1110+
return index;
11001111
}
11011112

1102-
#ifdef CONFIG_SWIOTLB_DYNAMIC
1103-
11041113
/**
11051114
* swiotlb_find_slots() - search for slots in the whole swiotlb
11061115
* @dev: Device which maps the buffer.
@@ -1124,18 +1133,17 @@ static int swiotlb_find_slots(struct device *dev, phys_addr_t orig_addr,
11241133
unsigned long nslabs;
11251134
unsigned long flags;
11261135
u64 phys_limit;
1136+
int cpu, i;
11271137
int index;
11281138

1129-
rcu_read_lock();
1130-
list_for_each_entry_rcu(pool, &mem->pools, node) {
1131-
index = swiotlb_pool_find_slots(dev, pool, orig_addr,
1132-
alloc_size, alloc_align_mask);
1133-
if (index >= 0) {
1134-
rcu_read_unlock();
1139+
cpu = raw_smp_processor_id();
1140+
for (i = 0; i < default_nareas; ++i) {
1141+
index = swiotlb_search_area(dev, cpu, i, orig_addr, alloc_size,
1142+
alloc_align_mask, &pool);
1143+
if (index >= 0)
11351144
goto found;
1136-
}
11371145
}
1138-
rcu_read_unlock();
1146+
11391147
if (!mem->can_grow)
11401148
return -1;
11411149

@@ -1148,8 +1156,8 @@ static int swiotlb_find_slots(struct device *dev, phys_addr_t orig_addr,
11481156
if (!pool)
11491157
return -1;
11501158

1151-
index = swiotlb_pool_find_slots(dev, pool, orig_addr,
1152-
alloc_size, alloc_align_mask);
1159+
index = swiotlb_search_pool_area(dev, pool, 0, orig_addr,
1160+
alloc_size, alloc_align_mask);
11531161
if (index < 0) {
11541162
swiotlb_dyn_free(&pool->rcu);
11551163
return -1;
@@ -1192,9 +1200,21 @@ static int swiotlb_find_slots(struct device *dev, phys_addr_t orig_addr,
11921200
size_t alloc_size, unsigned int alloc_align_mask,
11931201
struct io_tlb_pool **retpool)
11941202
{
1195-
*retpool = &dev->dma_io_tlb_mem->defpool;
1196-
return swiotlb_pool_find_slots(dev, *retpool,
1197-
orig_addr, alloc_size, alloc_align_mask);
1203+
struct io_tlb_pool *pool;
1204+
int start, i;
1205+
int index;
1206+
1207+
*retpool = pool = &dev->dma_io_tlb_mem->defpool;
1208+
i = start = raw_smp_processor_id() & (pool->nareas - 1);
1209+
do {
1210+
index = swiotlb_search_pool_area(dev, pool, i, orig_addr,
1211+
alloc_size, alloc_align_mask);
1212+
if (index >= 0)
1213+
return index;
1214+
if (++i >= pool->nareas)
1215+
i = 0;
1216+
} while (i != start);
1217+
return -1;
11981218
}
11991219

12001220
#endif /* CONFIG_SWIOTLB_DYNAMIC */

0 commit comments

Comments
 (0)