Skip to content

Commit 54d7431

Browse files
Alexandre Ghitipalmer-dabbelt
authored andcommitted
riscv: Add support for BATCHED_UNMAP_TLB_FLUSH
Allow to defer the flushing of the TLB when unmapping pages, which allows to reduce the numbers of IPI and the number of sfence.vma. The ubenchmarch used in commit 43b3dfd ("arm64: support batched/deferred tlb shootdown during page reclamation/migration") that was multithreaded to force the usage of IPI shows good performance improvement on all platforms: * Unmatched: ~34% * TH1520 : ~78% * Qemu : ~81% In addition, perf on qemu reports an important decrease in time spent dealing with IPIs: Before: 68.17% main [kernel.kallsyms] [k] __sbi_rfence_v02_call After : 8.64% main [kernel.kallsyms] [k] __sbi_rfence_v02_call * Benchmark: int stick_this_thread_to_core(int core_id) { int num_cores = sysconf(_SC_NPROCESSORS_ONLN); if (core_id < 0 || core_id >= num_cores) return EINVAL; cpu_set_t cpuset; CPU_ZERO(&cpuset); CPU_SET(core_id, &cpuset); pthread_t current_thread = pthread_self(); return pthread_setaffinity_np(current_thread, sizeof(cpu_set_t), &cpuset); } static void *fn_thread (void *p_data) { int ret; pthread_t thread; stick_this_thread_to_core((int)p_data); while (1) { sleep(1); } return NULL; } int main() { volatile unsigned char *p = mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); pthread_t threads[4]; int ret; for (int i = 0; i < 4; ++i) { ret = pthread_create(&threads[i], NULL, fn_thread, (void *)i); if (ret) { printf("%s", strerror (ret)); } } memset(p, 0x88, SIZE); for (int k = 0; k < 10000; k++) { /* swap in */ for (int i = 0; i < SIZE; i += 4096) { (void)p[i]; } /* swap out */ madvise(p, SIZE, MADV_PAGEOUT); } for (int i = 0; i < 4; i++) { pthread_cancel(threads[i]); } for (int i = 0; i < 4; i++) { pthread_join(threads[i], NULL); } return 0; } Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com> Reviewed-by: Jisheng Zhang <jszhang@kernel.org> Tested-by: Jisheng Zhang <jszhang@kernel.org> # Tested on TH1520 Tested-by: Nam Cao <namcao@linutronix.de> Link: https://lore.kernel.org/r/20240108193640.344929-1-alexghiti@rivosinc.com Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
1 parent ff172d4 commit 54d7431

File tree

5 files changed

+74
-21
lines changed

5 files changed

+74
-21
lines changed

Documentation/features/vm/TLB/arch-support.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
| openrisc: | .. |
2121
| parisc: | TODO |
2222
| powerpc: | TODO |
23-
| riscv: | TODO |
23+
| riscv: | ok |
2424
| s390: | TODO |
2525
| sh: | TODO |
2626
| sparc: | TODO |

arch/riscv/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ config RISCV
5353
select ARCH_USE_MEMTEST
5454
select ARCH_USE_QUEUED_RWLOCKS
5555
select ARCH_USES_CFI_TRAPS if CFI_CLANG
56+
select ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH if SMP && MMU
5657
select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT if MMU
5758
select ARCH_WANT_FRAME_POINTERS
5859
select ARCH_WANT_GENERAL_HUGETLB if !RISCV_ISA_SVNAPOT

arch/riscv/include/asm/tlbbatch.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
/*
3+
* Copyright (C) 2023 Rivos Inc.
4+
*/
5+
6+
#ifndef _ASM_RISCV_TLBBATCH_H
7+
#define _ASM_RISCV_TLBBATCH_H
8+
9+
#include <linux/cpumask.h>
10+
11+
struct arch_tlbflush_unmap_batch {
12+
struct cpumask cpumask;
13+
};
14+
15+
#endif /* _ASM_RISCV_TLBBATCH_H */

arch/riscv/include/asm/tlbflush.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,14 @@ void flush_tlb_kernel_range(unsigned long start, unsigned long end);
4646
void flush_pmd_tlb_range(struct vm_area_struct *vma, unsigned long start,
4747
unsigned long end);
4848
#endif
49+
50+
bool arch_tlbbatch_should_defer(struct mm_struct *mm);
51+
void arch_tlbbatch_add_pending(struct arch_tlbflush_unmap_batch *batch,
52+
struct mm_struct *mm,
53+
unsigned long uaddr);
54+
void arch_flush_tlb_batched_pending(struct mm_struct *mm);
55+
void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch);
56+
4957
#else /* CONFIG_SMP && CONFIG_MMU */
5058

5159
#define flush_tlb_all() local_flush_tlb_all()

arch/riscv/mm/tlbflush.c

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -93,29 +93,23 @@ static void __ipi_flush_tlb_range_asid(void *info)
9393
local_flush_tlb_range_asid(d->start, d->size, d->stride, d->asid);
9494
}
9595

96-
static void __flush_tlb_range(struct mm_struct *mm, unsigned long start,
97-
unsigned long size, unsigned long stride)
96+
static void __flush_tlb_range(struct cpumask *cmask, unsigned long asid,
97+
unsigned long start, unsigned long size,
98+
unsigned long stride)
9899
{
99100
struct flush_tlb_range_data ftd;
100-
const struct cpumask *cmask;
101-
unsigned long asid = FLUSH_TLB_NO_ASID;
102101
bool broadcast;
103102

104-
if (mm) {
105-
unsigned int cpuid;
103+
if (cpumask_empty(cmask))
104+
return;
106105

107-
cmask = mm_cpumask(mm);
108-
if (cpumask_empty(cmask))
109-
return;
106+
if (cmask != cpu_online_mask) {
107+
unsigned int cpuid;
110108

111109
cpuid = get_cpu();
112110
/* check if the tlbflush needs to be sent to other CPUs */
113111
broadcast = cpumask_any_but(cmask, cpuid) < nr_cpu_ids;
114-
115-
if (static_branch_unlikely(&use_asid_allocator))
116-
asid = atomic_long_read(&mm->context.id) & asid_mask;
117112
} else {
118-
cmask = cpu_online_mask;
119113
broadcast = true;
120114
}
121115

@@ -135,25 +129,34 @@ static void __flush_tlb_range(struct mm_struct *mm, unsigned long start,
135129
local_flush_tlb_range_asid(start, size, stride, asid);
136130
}
137131

138-
if (mm)
132+
if (cmask != cpu_online_mask)
139133
put_cpu();
140134
}
141135

136+
static inline unsigned long get_mm_asid(struct mm_struct *mm)
137+
{
138+
return static_branch_unlikely(&use_asid_allocator) ?
139+
atomic_long_read(&mm->context.id) & asid_mask : FLUSH_TLB_NO_ASID;
140+
}
141+
142142
void flush_tlb_mm(struct mm_struct *mm)
143143
{
144-
__flush_tlb_range(mm, 0, FLUSH_TLB_MAX_SIZE, PAGE_SIZE);
144+
__flush_tlb_range(mm_cpumask(mm), get_mm_asid(mm),
145+
0, FLUSH_TLB_MAX_SIZE, PAGE_SIZE);
145146
}
146147

147148
void flush_tlb_mm_range(struct mm_struct *mm,
148149
unsigned long start, unsigned long end,
149150
unsigned int page_size)
150151
{
151-
__flush_tlb_range(mm, start, end - start, page_size);
152+
__flush_tlb_range(mm_cpumask(mm), get_mm_asid(mm),
153+
start, end - start, page_size);
152154
}
153155

154156
void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
155157
{
156-
__flush_tlb_range(vma->vm_mm, addr, PAGE_SIZE, PAGE_SIZE);
158+
__flush_tlb_range(mm_cpumask(vma->vm_mm), get_mm_asid(vma->vm_mm),
159+
addr, PAGE_SIZE, PAGE_SIZE);
157160
}
158161

159162
void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
@@ -185,18 +188,44 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
185188
}
186189
}
187190

188-
__flush_tlb_range(vma->vm_mm, start, end - start, stride_size);
191+
__flush_tlb_range(mm_cpumask(vma->vm_mm), get_mm_asid(vma->vm_mm),
192+
start, end - start, stride_size);
189193
}
190194

191195
void flush_tlb_kernel_range(unsigned long start, unsigned long end)
192196
{
193-
__flush_tlb_range(NULL, start, end - start, PAGE_SIZE);
197+
__flush_tlb_range((struct cpumask *)cpu_online_mask, FLUSH_TLB_NO_ASID,
198+
start, end - start, PAGE_SIZE);
194199
}
195200

196201
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
197202
void flush_pmd_tlb_range(struct vm_area_struct *vma, unsigned long start,
198203
unsigned long end)
199204
{
200-
__flush_tlb_range(vma->vm_mm, start, end - start, PMD_SIZE);
205+
__flush_tlb_range(mm_cpumask(vma->vm_mm), get_mm_asid(vma->vm_mm),
206+
start, end - start, PMD_SIZE);
201207
}
202208
#endif
209+
210+
bool arch_tlbbatch_should_defer(struct mm_struct *mm)
211+
{
212+
return true;
213+
}
214+
215+
void arch_tlbbatch_add_pending(struct arch_tlbflush_unmap_batch *batch,
216+
struct mm_struct *mm,
217+
unsigned long uaddr)
218+
{
219+
cpumask_or(&batch->cpumask, &batch->cpumask, mm_cpumask(mm));
220+
}
221+
222+
void arch_flush_tlb_batched_pending(struct mm_struct *mm)
223+
{
224+
flush_tlb_mm(mm);
225+
}
226+
227+
void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch)
228+
{
229+
__flush_tlb_range(&batch->cpumask, FLUSH_TLB_NO_ASID, 0,
230+
FLUSH_TLB_MAX_SIZE, PAGE_SIZE);
231+
}

0 commit comments

Comments
 (0)