forked from mirrors/linux
		
	scripts: ftrace - move the sort-processing in ftrace_init
When the kernel starts, the initialization of ftrace takes up a portion of the time (approximately 6~8ms) to sort mcount addresses. We can save this time by moving mcount-sorting to compile time. Link: https://lkml.kernel.org/r/20211212113358.34208-2-yinan@linux.alibaba.com Signed-off-by: Yinan Liu <yinan@linux.alibaba.com> Reported-by: kernel test robot <lkp@intel.com> Reported-by: kernel test robot <oliver.sang@intel.com> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
This commit is contained in:
		
							parent
							
								
									1c1857d400
								
							
						
					
					
						commit
						72b3942a17
					
				
					 5 changed files with 137 additions and 8 deletions
				
			
		|  | @ -6406,8 +6406,15 @@ static int ftrace_process_locs(struct module *mod, | ||||||
| 	if (!count) | 	if (!count) | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	sort(start, count, sizeof(*start), | 	/*
 | ||||||
| 	     ftrace_cmp_ips, NULL); | 	 * Sorting mcount in vmlinux at build time depend on | ||||||
|  | 	 * CONFIG_BUILDTIME_TABLE_SORT, while mcount loc in | ||||||
|  | 	 * modules can not be sorted at build time. | ||||||
|  | 	 */ | ||||||
|  | 	if (!IS_ENABLED(CONFIG_BUILDTIME_TABLE_SORT) || mod) { | ||||||
|  | 		sort(start, count, sizeof(*start), | ||||||
|  | 		     ftrace_cmp_ips, NULL); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	start_pg = ftrace_allocate_pages(count); | 	start_pg = ftrace_allocate_pages(count); | ||||||
| 	if (!start_pg) | 	if (!start_pg) | ||||||
|  |  | ||||||
|  | @ -17,6 +17,7 @@ hostprogs-always-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE)	+= insert-sys-cert | ||||||
| hostprogs-always-$(CONFIG_SYSTEM_REVOCATION_LIST)	+= extract-cert | hostprogs-always-$(CONFIG_SYSTEM_REVOCATION_LIST)	+= extract-cert | ||||||
| 
 | 
 | ||||||
| HOSTCFLAGS_sorttable.o = -I$(srctree)/tools/include | HOSTCFLAGS_sorttable.o = -I$(srctree)/tools/include | ||||||
|  | HOSTLDLIBS_sorttable = -lpthread | ||||||
| HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include | HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include | ||||||
| HOSTCFLAGS_sign-file.o = $(CRYPTO_CFLAGS) | HOSTCFLAGS_sign-file.o = $(CRYPTO_CFLAGS) | ||||||
| HOSTLDLIBS_sign-file = $(CRYPTO_LIBS) | HOSTLDLIBS_sign-file = $(CRYPTO_LIBS) | ||||||
|  | @ -29,7 +30,10 @@ ARCH := x86 | ||||||
| endif | endif | ||||||
| HOSTCFLAGS_sorttable.o += -I$(srctree)/tools/arch/x86/include | HOSTCFLAGS_sorttable.o += -I$(srctree)/tools/arch/x86/include | ||||||
| HOSTCFLAGS_sorttable.o += -DUNWINDER_ORC_ENABLED | HOSTCFLAGS_sorttable.o += -DUNWINDER_ORC_ENABLED | ||||||
| HOSTLDLIBS_sorttable = -lpthread | endif | ||||||
|  | 
 | ||||||
|  | ifdef CONFIG_DYNAMIC_FTRACE | ||||||
|  | HOSTCFLAGS_sorttable.o += -DMCOUNT_SORT_ENABLED | ||||||
| endif | endif | ||||||
| 
 | 
 | ||||||
| # The following programs are only built on demand
 | # The following programs are only built on demand
 | ||||||
|  |  | ||||||
|  | @ -400,6 +400,9 @@ if [ -n "${CONFIG_DEBUG_INFO_BTF}" -a -n "${CONFIG_BPF}" ]; then | ||||||
| 	${RESOLVE_BTFIDS} vmlinux | 	${RESOLVE_BTFIDS} vmlinux | ||||||
| fi | fi | ||||||
| 
 | 
 | ||||||
|  | info SYSMAP System.map | ||||||
|  | mksysmap vmlinux System.map | ||||||
|  | 
 | ||||||
| if [ -n "${CONFIG_BUILDTIME_TABLE_SORT}" ]; then | if [ -n "${CONFIG_BUILDTIME_TABLE_SORT}" ]; then | ||||||
| 	info SORTTAB vmlinux | 	info SORTTAB vmlinux | ||||||
| 	if ! sorttable vmlinux; then | 	if ! sorttable vmlinux; then | ||||||
|  | @ -408,9 +411,6 @@ if [ -n "${CONFIG_BUILDTIME_TABLE_SORT}" ]; then | ||||||
| 	fi | 	fi | ||||||
| fi | fi | ||||||
| 
 | 
 | ||||||
| info SYSMAP System.map |  | ||||||
| mksysmap vmlinux System.map |  | ||||||
| 
 |  | ||||||
| # step a (see comment above) | # step a (see comment above) | ||||||
| if [ -n "${CONFIG_KALLSYMS}" ]; then | if [ -n "${CONFIG_KALLSYMS}" ]; then | ||||||
| 	mksysmap ${kallsyms_vmlinux} .tmp_System.map | 	mksysmap ${kallsyms_vmlinux} .tmp_System.map | ||||||
|  |  | ||||||
|  | @ -30,6 +30,8 @@ | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
|  | #include <errno.h> | ||||||
|  | #include <pthread.h> | ||||||
| 
 | 
 | ||||||
| #include <tools/be_byteshift.h> | #include <tools/be_byteshift.h> | ||||||
| #include <tools/le_byteshift.h> | #include <tools/le_byteshift.h> | ||||||
|  |  | ||||||
|  | @ -19,6 +19,9 @@ | ||||||
| 
 | 
 | ||||||
| #undef extable_ent_size | #undef extable_ent_size | ||||||
| #undef compare_extable | #undef compare_extable | ||||||
|  | #undef get_mcount_loc | ||||||
|  | #undef sort_mcount_loc | ||||||
|  | #undef elf_mcount_loc | ||||||
| #undef do_sort | #undef do_sort | ||||||
| #undef Elf_Addr | #undef Elf_Addr | ||||||
| #undef Elf_Ehdr | #undef Elf_Ehdr | ||||||
|  | @ -41,6 +44,9 @@ | ||||||
| #ifdef SORTTABLE_64 | #ifdef SORTTABLE_64 | ||||||
| # define extable_ent_size	16 | # define extable_ent_size	16 | ||||||
| # define compare_extable	compare_extable_64 | # define compare_extable	compare_extable_64 | ||||||
|  | # define get_mcount_loc		get_mcount_loc_64 | ||||||
|  | # define sort_mcount_loc	sort_mcount_loc_64 | ||||||
|  | # define elf_mcount_loc		elf_mcount_loc_64 | ||||||
| # define do_sort		do_sort_64 | # define do_sort		do_sort_64 | ||||||
| # define Elf_Addr		Elf64_Addr | # define Elf_Addr		Elf64_Addr | ||||||
| # define Elf_Ehdr		Elf64_Ehdr | # define Elf_Ehdr		Elf64_Ehdr | ||||||
|  | @ -62,6 +68,9 @@ | ||||||
| #else | #else | ||||||
| # define extable_ent_size	8 | # define extable_ent_size	8 | ||||||
| # define compare_extable	compare_extable_32 | # define compare_extable	compare_extable_32 | ||||||
|  | # define get_mcount_loc		get_mcount_loc_32 | ||||||
|  | # define sort_mcount_loc	sort_mcount_loc_32 | ||||||
|  | # define elf_mcount_loc		elf_mcount_loc_32 | ||||||
| # define do_sort		do_sort_32 | # define do_sort		do_sort_32 | ||||||
| # define Elf_Addr		Elf32_Addr | # define Elf_Addr		Elf32_Addr | ||||||
| # define Elf_Ehdr		Elf32_Ehdr | # define Elf_Ehdr		Elf32_Ehdr | ||||||
|  | @ -84,8 +93,6 @@ | ||||||
| 
 | 
 | ||||||
| #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED) | #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED) | ||||||
| /* ORC unwinder only support X86_64 */ | /* ORC unwinder only support X86_64 */ | ||||||
| #include <errno.h> |  | ||||||
| #include <pthread.h> |  | ||||||
| #include <asm/orc_types.h> | #include <asm/orc_types.h> | ||||||
| 
 | 
 | ||||||
| #define ERRSTR_MAXSZ	256 | #define ERRSTR_MAXSZ	256 | ||||||
|  | @ -191,7 +198,64 @@ static int compare_extable(const void *a, const void *b) | ||||||
| 		return 1; | 		return 1; | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  | #ifdef MCOUNT_SORT_ENABLED | ||||||
|  | struct elf_mcount_loc { | ||||||
|  | 	Elf_Ehdr *ehdr; | ||||||
|  | 	Elf_Shdr *init_data_sec; | ||||||
|  | 	uint_t start_mcount_loc; | ||||||
|  | 	uint_t stop_mcount_loc; | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
|  | /* Sort the addresses stored between __start_mcount_loc to __stop_mcount_loc in vmlinux */ | ||||||
|  | static void *sort_mcount_loc(void *arg) | ||||||
|  | { | ||||||
|  | 	struct elf_mcount_loc *emloc = (struct elf_mcount_loc *)arg; | ||||||
|  | 	uint_t offset = emloc->start_mcount_loc - _r(&(emloc->init_data_sec)->sh_addr) | ||||||
|  | 					+ _r(&(emloc->init_data_sec)->sh_offset); | ||||||
|  | 	uint_t count = emloc->stop_mcount_loc - emloc->start_mcount_loc; | ||||||
|  | 	unsigned char *start_loc = (void *)emloc->ehdr + offset; | ||||||
|  | 
 | ||||||
|  | 	qsort(start_loc, count/sizeof(uint_t), sizeof(uint_t), compare_extable); | ||||||
|  | 	return NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Get the address of __start_mcount_loc and __stop_mcount_loc in System.map */ | ||||||
|  | static void get_mcount_loc(uint_t *_start, uint_t *_stop) | ||||||
|  | { | ||||||
|  | 	FILE *file_start, *file_stop; | ||||||
|  | 	char start_buff[20]; | ||||||
|  | 	char stop_buff[20]; | ||||||
|  | 	int len = 0; | ||||||
|  | 
 | ||||||
|  | 	file_start = popen(" grep start_mcount System.map | awk '{print $1}' ", "r"); | ||||||
|  | 	if (!file_start) { | ||||||
|  | 		fprintf(stderr, "get start_mcount_loc error!"); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	file_stop = popen(" grep stop_mcount System.map | awk '{print $1}' ", "r"); | ||||||
|  | 	if (!file_stop) { | ||||||
|  | 		fprintf(stderr, "get stop_mcount_loc error!"); | ||||||
|  | 		pclose(file_start); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	while (fgets(start_buff, sizeof(start_buff), file_start) != NULL) { | ||||||
|  | 		len = strlen(start_buff); | ||||||
|  | 		start_buff[len - 1] = '\0'; | ||||||
|  | 	} | ||||||
|  | 	*_start = strtoul(start_buff, NULL, 16); | ||||||
|  | 
 | ||||||
|  | 	while (fgets(stop_buff, sizeof(stop_buff), file_stop) != NULL) { | ||||||
|  | 		len = strlen(stop_buff); | ||||||
|  | 		stop_buff[len - 1] = '\0'; | ||||||
|  | 	} | ||||||
|  | 	*_stop = strtoul(stop_buff, NULL, 16); | ||||||
|  | 
 | ||||||
|  | 	pclose(file_start); | ||||||
|  | 	pclose(file_stop); | ||||||
|  | } | ||||||
|  | #endif | ||||||
| static int do_sort(Elf_Ehdr *ehdr, | static int do_sort(Elf_Ehdr *ehdr, | ||||||
| 		   char const *const fname, | 		   char const *const fname, | ||||||
| 		   table_sort_t custom_sort) | 		   table_sort_t custom_sort) | ||||||
|  | @ -217,6 +281,12 @@ static int do_sort(Elf_Ehdr *ehdr, | ||||||
| 	int idx; | 	int idx; | ||||||
| 	unsigned int shnum; | 	unsigned int shnum; | ||||||
| 	unsigned int shstrndx; | 	unsigned int shstrndx; | ||||||
|  | #ifdef MCOUNT_SORT_ENABLED | ||||||
|  | 	struct elf_mcount_loc mstruct; | ||||||
|  | 	uint_t _start_mcount_loc = 0; | ||||||
|  | 	uint_t _stop_mcount_loc = 0; | ||||||
|  | 	pthread_t mcount_sort_thread; | ||||||
|  | #endif | ||||||
| #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED) | #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED) | ||||||
| 	unsigned int orc_ip_size = 0; | 	unsigned int orc_ip_size = 0; | ||||||
| 	unsigned int orc_size = 0; | 	unsigned int orc_size = 0; | ||||||
|  | @ -253,6 +323,17 @@ static int do_sort(Elf_Ehdr *ehdr, | ||||||
| 			symtab_shndx = (Elf32_Word *)((const char *)ehdr + | 			symtab_shndx = (Elf32_Word *)((const char *)ehdr + | ||||||
| 						      _r(&s->sh_offset)); | 						      _r(&s->sh_offset)); | ||||||
| 
 | 
 | ||||||
|  | #ifdef MCOUNT_SORT_ENABLED | ||||||
|  | 		/* locate the .init.data section in vmlinux */ | ||||||
|  | 		if (!strcmp(secstrings + idx, ".init.data")) { | ||||||
|  | 			get_mcount_loc(&_start_mcount_loc, &_stop_mcount_loc); | ||||||
|  | 			mstruct.ehdr = ehdr; | ||||||
|  | 			mstruct.init_data_sec = s; | ||||||
|  | 			mstruct.start_mcount_loc = _start_mcount_loc; | ||||||
|  | 			mstruct.stop_mcount_loc = _stop_mcount_loc; | ||||||
|  | 		} | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED) | #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED) | ||||||
| 		/* locate the ORC unwind tables */ | 		/* locate the ORC unwind tables */ | ||||||
| 		if (!strcmp(secstrings + idx, ".orc_unwind_ip")) { | 		if (!strcmp(secstrings + idx, ".orc_unwind_ip")) { | ||||||
|  | @ -294,6 +375,23 @@ static int do_sort(Elf_Ehdr *ehdr, | ||||||
| 		goto out; | 		goto out; | ||||||
| 	} | 	} | ||||||
| #endif | #endif | ||||||
|  | 
 | ||||||
|  | #ifdef MCOUNT_SORT_ENABLED | ||||||
|  | 	if (!mstruct.init_data_sec || !_start_mcount_loc || !_stop_mcount_loc) { | ||||||
|  | 		fprintf(stderr, | ||||||
|  | 			"incomplete mcount's sort in file: %s\n", | ||||||
|  | 			fname); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* create thread to sort mcount_loc concurrently */ | ||||||
|  | 	if (pthread_create(&mcount_sort_thread, NULL, &sort_mcount_loc, &mstruct)) { | ||||||
|  | 		fprintf(stderr, | ||||||
|  | 			"pthread_create mcount_sort_thread failed '%s': %s\n", | ||||||
|  | 			strerror(errno), fname); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | #endif | ||||||
| 	if (!extab_sec) { | 	if (!extab_sec) { | ||||||
| 		fprintf(stderr,	"no __ex_table in file: %s\n", fname); | 		fprintf(stderr,	"no __ex_table in file: %s\n", fname); | ||||||
| 		goto out; | 		goto out; | ||||||
|  | @ -376,5 +474,23 @@ static int do_sort(Elf_Ehdr *ehdr, | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| #endif | #endif | ||||||
|  | 
 | ||||||
|  | #ifdef MCOUNT_SORT_ENABLED | ||||||
|  | 	if (mcount_sort_thread) { | ||||||
|  | 		void *retval = NULL; | ||||||
|  | 		/* wait for mcount sort done */ | ||||||
|  | 		rc = pthread_join(mcount_sort_thread, &retval); | ||||||
|  | 		if (rc) { | ||||||
|  | 			fprintf(stderr, | ||||||
|  | 				"pthread_join failed '%s': %s\n", | ||||||
|  | 				strerror(errno), fname); | ||||||
|  | 		} else if (retval) { | ||||||
|  | 			rc = -1; | ||||||
|  | 			fprintf(stderr, | ||||||
|  | 				"failed to sort mcount '%s': %s\n", | ||||||
|  | 				(char *)retval, fname); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | #endif | ||||||
| 	return rc; | 	return rc; | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Yinan Liu
						Yinan Liu