mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	sched, x86: Optimize the preempt_schedule() call
Remove the bloat of the C calling convention out of the
preempt_enable() sites by creating an ASM wrapper which allows us to
do an asm("call ___preempt_schedule") instead.
calling.h bits by Andi Kleen
Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/n/tip-tk7xdi1cvvxewixzke8t8le1@git.kernel.org
[ Fixed build error. ]
Signed-off-by: Ingo Molnar <mingo@kernel.org>
			
			
This commit is contained in:
		
							parent
							
								
									c2daa3bed5
								
							
						
					
					
						commit
						1a338ac32c
					
				
					 8 changed files with 116 additions and 8 deletions
				
			
		| 
						 | 
				
			
			@ -48,6 +48,8 @@ For 32-bit we have the following conventions - kernel is built with
 | 
			
		|||
 | 
			
		||||
#include <asm/dwarf2.h>
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_X86_64
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * 64-bit system call stack frame layout defines and helpers,
 | 
			
		||||
 * for assembly code:
 | 
			
		||||
| 
						 | 
				
			
			@ -192,3 +194,51 @@ For 32-bit we have the following conventions - kernel is built with
 | 
			
		|||
	.macro icebp
 | 
			
		||||
	.byte 0xf1
 | 
			
		||||
	.endm
 | 
			
		||||
 | 
			
		||||
#else /* CONFIG_X86_64 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * For 32bit only simplified versions of SAVE_ALL/RESTORE_ALL. These
 | 
			
		||||
 * are different from the entry_32.S versions in not changing the segment
 | 
			
		||||
 * registers. So only suitable for in kernel use, not when transitioning
 | 
			
		||||
 * from or to user space. The resulting stack frame is not a standard
 | 
			
		||||
 * pt_regs frame. The main use case is calling C code from assembler
 | 
			
		||||
 * when all the registers need to be preserved.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
	.macro SAVE_ALL
 | 
			
		||||
	pushl_cfi %eax
 | 
			
		||||
	CFI_REL_OFFSET eax, 0
 | 
			
		||||
	pushl_cfi %ebp
 | 
			
		||||
	CFI_REL_OFFSET ebp, 0
 | 
			
		||||
	pushl_cfi %edi
 | 
			
		||||
	CFI_REL_OFFSET edi, 0
 | 
			
		||||
	pushl_cfi %esi
 | 
			
		||||
	CFI_REL_OFFSET esi, 0
 | 
			
		||||
	pushl_cfi %edx
 | 
			
		||||
	CFI_REL_OFFSET edx, 0
 | 
			
		||||
	pushl_cfi %ecx
 | 
			
		||||
	CFI_REL_OFFSET ecx, 0
 | 
			
		||||
	pushl_cfi %ebx
 | 
			
		||||
	CFI_REL_OFFSET ebx, 0
 | 
			
		||||
	.endm
 | 
			
		||||
 | 
			
		||||
	.macro RESTORE_ALL
 | 
			
		||||
	popl_cfi %ebx
 | 
			
		||||
	CFI_RESTORE ebx
 | 
			
		||||
	popl_cfi %ecx
 | 
			
		||||
	CFI_RESTORE ecx
 | 
			
		||||
	popl_cfi %edx
 | 
			
		||||
	CFI_RESTORE edx
 | 
			
		||||
	popl_cfi %esi
 | 
			
		||||
	CFI_RESTORE esi
 | 
			
		||||
	popl_cfi %edi
 | 
			
		||||
	CFI_RESTORE edi
 | 
			
		||||
	popl_cfi %ebp
 | 
			
		||||
	CFI_RESTORE ebp
 | 
			
		||||
	popl_cfi %eax
 | 
			
		||||
	CFI_RESTORE eax
 | 
			
		||||
	.endm
 | 
			
		||||
 | 
			
		||||
#endif /* CONFIG_X86_64 */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -95,4 +95,14 @@ static __always_inline bool should_resched(void)
 | 
			
		|||
	return unlikely(!__this_cpu_read_4(__preempt_count));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PREEMPT
 | 
			
		||||
  extern asmlinkage void ___preempt_schedule(void);
 | 
			
		||||
# define __preempt_schedule() asm ("call ___preempt_schedule")
 | 
			
		||||
  extern asmlinkage void preempt_schedule(void);
 | 
			
		||||
# ifdef CONFIG_CONTEXT_TRACKING
 | 
			
		||||
    extern asmlinkage void ___preempt_schedule_context(void);
 | 
			
		||||
#   define __preempt_schedule_context() asm ("call ___preempt_schedule_context")
 | 
			
		||||
# endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __ASM_PREEMPT_H */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,6 +36,8 @@ obj-y			+= tsc.o io_delay.o rtc.o
 | 
			
		|||
obj-y			+= pci-iommu_table.o
 | 
			
		||||
obj-y			+= resource.o
 | 
			
		||||
 | 
			
		||||
obj-$(CONFIG_PREEMPT)	+= preempt.o
 | 
			
		||||
 | 
			
		||||
obj-y				+= process.o
 | 
			
		||||
obj-y				+= i387.o xsave.o
 | 
			
		||||
obj-y				+= ptrace.o
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,3 +37,10 @@ EXPORT_SYMBOL(strstr);
 | 
			
		|||
 | 
			
		||||
EXPORT_SYMBOL(csum_partial);
 | 
			
		||||
EXPORT_SYMBOL(empty_zero_page);
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PREEMPT
 | 
			
		||||
EXPORT_SYMBOL(___preempt_schedule);
 | 
			
		||||
#ifdef CONFIG_CONTEXT_TRACKING
 | 
			
		||||
EXPORT_SYMBOL(___preempt_schedule_context);
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										25
									
								
								arch/x86/kernel/preempt.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								arch/x86/kernel/preempt.S
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,25 @@
 | 
			
		|||
 | 
			
		||||
#include <linux/linkage.h>
 | 
			
		||||
#include <asm/dwarf2.h>
 | 
			
		||||
#include <asm/asm.h>
 | 
			
		||||
#include <asm/calling.h>
 | 
			
		||||
 | 
			
		||||
ENTRY(___preempt_schedule)
 | 
			
		||||
	CFI_STARTPROC
 | 
			
		||||
	SAVE_ALL
 | 
			
		||||
	call preempt_schedule
 | 
			
		||||
	RESTORE_ALL
 | 
			
		||||
	ret
 | 
			
		||||
	CFI_ENDPROC
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_CONTEXT_TRACKING
 | 
			
		||||
 | 
			
		||||
ENTRY(___preempt_schedule_context)
 | 
			
		||||
	CFI_STARTPROC
 | 
			
		||||
	SAVE_ALL
 | 
			
		||||
	call preempt_schedule_context
 | 
			
		||||
	RESTORE_ALL
 | 
			
		||||
	ret
 | 
			
		||||
	CFI_ENDPROC
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -66,3 +66,10 @@ EXPORT_SYMBOL(empty_zero_page);
 | 
			
		|||
#ifndef CONFIG_PARAVIRT
 | 
			
		||||
EXPORT_SYMBOL(native_load_gs_index);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PREEMPT
 | 
			
		||||
EXPORT_SYMBOL(___preempt_schedule);
 | 
			
		||||
#ifdef CONFIG_CONTEXT_TRACKING
 | 
			
		||||
EXPORT_SYMBOL(___preempt_schedule_context);
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -100,4 +100,14 @@ static __always_inline bool should_resched(void)
 | 
			
		|||
	return unlikely(!*preempt_count_ptr());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PREEMPT
 | 
			
		||||
extern asmlinkage void preempt_schedule(void);
 | 
			
		||||
#define __preempt_schedule() preempt_schedule()
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_CONTEXT_TRACKING
 | 
			
		||||
extern asmlinkage void preempt_schedule_context(void);
 | 
			
		||||
#define __preempt_schedule_context() preempt_schedule_context()
 | 
			
		||||
#endif
 | 
			
		||||
#endif /* CONFIG_PREEMPT */
 | 
			
		||||
 | 
			
		||||
#endif /* __ASM_PREEMPT_H */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -50,18 +50,17 @@ do { \
 | 
			
		|||
#define preempt_enable_no_resched() sched_preempt_enable_no_resched()
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PREEMPT
 | 
			
		||||
asmlinkage void preempt_schedule(void);
 | 
			
		||||
#define preempt_enable() \
 | 
			
		||||
do { \
 | 
			
		||||
	barrier(); \
 | 
			
		||||
	if (unlikely(preempt_count_dec_and_test())) \
 | 
			
		||||
		preempt_schedule(); \
 | 
			
		||||
		__preempt_schedule(); \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define preempt_check_resched() \
 | 
			
		||||
do { \
 | 
			
		||||
	if (should_resched()) \
 | 
			
		||||
		preempt_schedule(); \
 | 
			
		||||
		__preempt_schedule(); \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
| 
						 | 
				
			
			@ -83,17 +82,15 @@ do { \
 | 
			
		|||
 | 
			
		||||
#ifdef CONFIG_PREEMPT
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_CONTEXT_TRACKING
 | 
			
		||||
asmlinkage void preempt_schedule_context(void);
 | 
			
		||||
#else
 | 
			
		||||
#define preempt_schedule_context() preempt_schedule()
 | 
			
		||||
#ifndef CONFIG_CONTEXT_TRACKING
 | 
			
		||||
#define __preempt_schedule_context() __preempt_schedule()
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define preempt_enable_notrace() \
 | 
			
		||||
do { \
 | 
			
		||||
	barrier(); \
 | 
			
		||||
	if (unlikely(__preempt_count_dec_and_test())) \
 | 
			
		||||
		preempt_schedule_context(); \
 | 
			
		||||
		__preempt_schedule_context(); \
 | 
			
		||||
} while (0)
 | 
			
		||||
#else
 | 
			
		||||
#define preempt_enable_notrace() preempt_enable_no_resched_notrace()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue