Skip to content
Permalink
Browse files
scripts: ftrace - move the sort-processing in ftrace_init to compile …
…time

When ftrace is enabled, ftrace_init will consume a period of
time, usually around 15~20 ms. Approximately 40% of the time is
consumed by sort-processing. Moving the sort-processing to the
compile time can speed up the kernel boot process.

performance test:
        env:    Intel(R) Xeon(R) CPU E5-2682 v4 @ 2.50GHz
        method: before and after patching, compare the
                total time of ftrace_init(), and verify
                the functionality of ftrace.

        avg_time of ftrace_init:
                with patch: 8.352 ms
                without patch: 15.763 ms

Signed-off-by: Yinan Liu <yinan@linux.alibaba.com>
  • Loading branch information
Yinan Liu authored and intel-lab-lkp committed Sep 11, 2021
1 parent 4034fb2 commit b629528c58117cccbdb70fbded8fd9c4ef2dd9d9
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 7 deletions.
@@ -6189,8 +6189,9 @@ static int ftrace_process_locs(struct module *mod,
if (!count)
return 0;

sort(start, count, sizeof(*start),
ftrace_cmp_ips, NULL);
if (mod)
sort(start, count, sizeof(*start),
ftrace_cmp_ips, NULL);

start_pg = ftrace_allocate_pages(count);
if (!start_pg)
@@ -422,6 +422,9 @@ if [ -n "${CONFIG_DEBUG_INFO_BTF}" -a -n "${CONFIG_BPF}" ]; then
${RESOLVE_BTFIDS} vmlinux
fi

info SYSMAP System.map
mksysmap vmlinux System.map

if [ -n "${CONFIG_BUILDTIME_TABLE_SORT}" ]; then
info SORTTAB vmlinux
if ! sorttable vmlinux; then
@@ -430,9 +433,6 @@ if [ -n "${CONFIG_BUILDTIME_TABLE_SORT}" ]; then
fi
fi

info SYSMAP System.map
mksysmap vmlinux System.map

# step a (see comment above)
if [ -n "${CONFIG_KALLSYMS}" ]; then
mksysmap ${kallsyms_vmlinux} .tmp_System.map
@@ -30,6 +30,8 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>

#include <tools/be_byteshift.h>
#include <tools/le_byteshift.h>
@@ -19,6 +19,9 @@

#undef extable_ent_size
#undef compare_extable
#undef get_mcount_loc
#undef sort_mcount_loc
#undef mcount_loc
#undef do_sort
#undef Elf_Addr
#undef Elf_Ehdr
@@ -41,6 +44,9 @@
#ifdef SORTTABLE_64
# define extable_ent_size 16
# define compare_extable compare_extable_64
# define get_mcount_loc get_mcount_loc_64
# define sort_mcount_loc sort_mcount_loc_64
# define mcount_loc mcount_loc_64
# define do_sort do_sort_64
# define Elf_Addr Elf64_Addr
# define Elf_Ehdr Elf64_Ehdr
@@ -62,6 +68,9 @@
#else
# define extable_ent_size 8
# define compare_extable compare_extable_32
# define get_mcount_loc get_mcount_loc_32
# define sort_mcount_loc sort_mcount_loc_32
# define mcount_loc mcount_loc_32
# define do_sort do_sort_32
# define Elf_Addr Elf32_Addr
# define Elf_Ehdr Elf32_Ehdr
@@ -84,8 +93,6 @@

#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
/* ORC unwinder only support X86_64 */
#include <errno.h>
#include <pthread.h>
#include <asm/orc_types.h>

#define ERRSTR_MAXSZ 256
@@ -191,6 +198,62 @@ static int compare_extable(const void *a, const void *b)
return 1;
return 0;
}
struct 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 to __stop_mcount */
static void *sort_mcount_loc(void *arg)
{
struct mcount_loc *mstruct = (struct mcount_loc *)arg;
uint_t offset = mstruct->start_mcount_loc - _r(&(mstruct->init_data_sec)->sh_addr)
+ _r(&(mstruct->init_data_sec)->sh_offset);
uint_t count = mstruct->stop_mcount_loc - mstruct->start_mcount_loc;
unsigned char *start = (void *)mstruct->ehdr + offset;

qsort(start, count/sizeof(uint_t), sizeof(uint_t), compare_extable);
return NULL;
}

/* get the address of __start_mcount_loc and __stop_mcount_loc*/
static void get_mcount_loc(uint_t *_start, uint_t *_stop)
{
FILE *file_start, *file_stop;
char start_buff[20];
char end_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(end_buff, sizeof(end_buff), file_stop) != NULL) {
len = strlen(end_buff);
end_buff[len - 1] = '\0';
}
*_stop = strtoul(end_buff, NULL, 16);

pclose(file_start);
pclose(file_stop);
}

static int do_sort(Elf_Ehdr *ehdr,
char const *const fname,
@@ -217,6 +280,10 @@ static int do_sort(Elf_Ehdr *ehdr,
int idx;
unsigned int shnum;
unsigned int shstrndx;
struct mcount_loc mstruct;
uint_t _start_mcount_loc = 0;
uint_t _stop_mcount_loc = 0;
pthread_t mcount_sort_thread;
#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
unsigned int orc_ip_size = 0;
unsigned int orc_size = 0;
@@ -253,6 +320,14 @@ static int do_sort(Elf_Ehdr *ehdr,
symtab_shndx = (Elf32_Word *)((const char *)ehdr +
_r(&s->sh_offset));

/* locate the mcount_loc */
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;
}
#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
/* locate the ORC unwind tables */
if (!strcmp(secstrings + idx, ".orc_unwind_ip")) {
@@ -294,6 +369,21 @@ static int do_sort(Elf_Ehdr *ehdr,
goto out;
}
#endif
if (!mstruct.init_data_sec || !_start_mcount_loc || !_stop_mcount_loc) {
fprintf(stderr,
"incomplete mcount_loc 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;
}

if (!extab_sec) {
fprintf(stderr, "no __ex_table in file: %s\n", fname);
goto out;
@@ -376,5 +466,20 @@ static int do_sort(Elf_Ehdr *ehdr,
}
}
#endif
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);
}
}
return rc;
}

0 comments on commit b629528

Please sign in to comment.