diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index 1967bd804..4e63d159c 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -454,6 +454,14 @@ static bool rela_equal(struct rela *rela1, struct rela *rela2) !strcmp(rela2->sym->name, ".altinstr_aux")) return true; + /* + * __llvm_prf_cnts is used by clang PGO to store counters. Ignore + * these to void unnecessary "changed function". + */ + if (!strcmp(rela1->sym->name, "__llvm_prf_cnts") && + !strcmp(rela2->sym->name, "__llvm_prf_cnts")) + return true; + /* * With -mcmodel=large on ppc64le, GCC might generate entries in the .toc * section for relocation symbol references. The .toc offsets may change @@ -986,6 +994,8 @@ static void kpatch_correlate_section(struct section *sec_orig, kpatch_correlate_symbol(sec_orig->sym, sec_patched->sym); } +static char *kpatch_section_function_name(struct section *sec); + static void kpatch_correlate_sections(struct list_head *seclist_orig, struct list_head *seclist_patched) { @@ -995,8 +1005,9 @@ static void kpatch_correlate_sections(struct list_head *seclist_orig, if (sec_orig->twin) continue; list_for_each_entry(sec_patched, seclist_patched, list) { - if (kpatch_mangled_strcmp(sec_orig->name, sec_patched->name) || - sec_patched->twin) + if (sec_patched->twin || + kpatch_mangled_strcmp(kpatch_section_function_name(sec_orig), + kpatch_section_function_name(sec_patched))) continue; if (is_special_static(is_rela_section(sec_orig) ? diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build index bec80102c..b9325b172 100755 --- a/kpatch-build/kpatch-build +++ b/kpatch-build/kpatch-build @@ -677,9 +677,10 @@ usage() { echo " --skip-cleanup Skip post-build cleanup" >&2 echo " --skip-compiler-check Skip compiler version matching check" >&2 echo " (not recommended)" >&2 + echo " -p, --profile-data specify profile data for PGO (clang only)" >&2 } -options="$(getopt -o ha:r:s:c:v:j:t:n:o:dR -l "help,archversion:,sourcerpm:,sourcedir:,config:,vmlinux:,jobs:,target:,name:,output:,oot-module:,oot-module-src:,debug,skip-gcc-check,skip-compiler-check,skip-cleanup,non-replace" -- "$@")" || die "getopt failed" +options="$(getopt -o ha:r:s:c:v:j:t:n:o:dRp: -l "help,archversion:,sourcerpm:,sourcedir:,config:,vmlinux:,jobs:,target:,name:,output:,oot-module:,oot-module-src:,debug,skip-gcc-check,skip-compiler-check,skip-cleanup,non-replace,profile-data" -- "$@")" || die "getopt failed" eval set -- "$options" @@ -761,6 +762,10 @@ while [[ $# -gt 0 ]]; do echo "WARNING: Skipping compiler version matching check (not recommended)" SKIPCOMPILERCHECK=1 ;; + -p|--profile-data) + PROFILE_DATA="$(readlink -f "$2")" + shift + ;; *) [[ "$1" = "--" ]] && shift && continue [[ ! -f "$1" ]] && die "patch file '$1' not found" @@ -1056,6 +1061,16 @@ fi if [[ -n "$CONFIG_CC_IS_CLANG" ]]; then echo "WARNING: Clang support is experimental" + if [[ -z "$PROFILE_DATA" ]] && [[ -n "$CONFIG_PGO_CLANG" ]]; then + die "Please specify profile-data for CONFIG_PGO_CLANG" + fi + if [[ -n "$PROFILE_DATA" ]] && [[ -z "$CONFIG_PGO_CLANG" ]]; then + echo "WARNING profile-data specified w/o CONFIG_PGO_CLANG, ignore it" + fi +else + if [[ -n "$PROFILE_DATA" ]]; then + die "Only supports profile-data with Clang" + fi fi if [[ "$SKIPCOMPILERCHECK" -eq 0 ]]; then @@ -1107,6 +1122,9 @@ declare -a MAKEVARS if [[ -n "$CONFIG_CC_IS_CLANG" ]]; then MAKEVARS+=("CC=${KPATCH_CC_PREFIX}${CLANG}") MAKEVARS+=("HOSTCC=clang") + if [[ -n "$CONFIG_PGO_CLANG" ]]; then + MAKEVARS+=("LLVM=1 CFLAGS_PGO_CLANG=-fprofile-use=$PROFILE_DATA") + fi else MAKEVARS+=("CC=${KPATCH_CC_PREFIX}${GCC}") fi diff --git a/kpatch-build/lookup.c b/kpatch-build/lookup.c index f2596b15f..bf23c329f 100644 --- a/kpatch-build/lookup.c +++ b/kpatch-build/lookup.c @@ -91,11 +91,13 @@ static bool maybe_discarded_sym(const char *name) } static bool locals_match(struct lookup_table *table, int idx, - struct symbol *file_sym, struct list_head *sym_list) + struct symbol *file_sym, struct list_head *sym_list, + int match_pct) { struct symbol *sym; struct object_symbol *table_sym; int i, found; + int match_cnt = 0, mismatch_cnt = 0; i = idx + 1; for_each_obj_symbol_continue(i, table_sym, table) { @@ -121,10 +123,18 @@ static bool locals_match(struct lookup_table *table, int idx, } } - if (!found) - return false; + if (found) + match_cnt++; + else + mismatch_cnt++; } + if (match_cnt * 100 < (match_cnt + mismatch_cnt) * match_pct) + return false; + + match_cnt = 0; + mismatch_cnt = 0; + sym = file_sym; list_for_each_entry_continue(sym, sym_list, list) { if (sym->type == STT_FILE) @@ -157,11 +167,13 @@ static bool locals_match(struct lookup_table *table, int idx, } } - if (!found) - return false; + if (found) + match_cnt++; + else + mismatch_cnt++; } - return true; + return match_cnt * 100 >= (match_cnt + mismatch_cnt) * match_pct; } static void find_local_syms(struct lookup_table *table, struct symbol *file_sym, @@ -176,7 +188,7 @@ static void find_local_syms(struct lookup_table *table, struct symbol *file_sym, continue; if (strcmp(file_sym->name, sym->name)) continue; - if (!locals_match(table, i, file_sym, sym_list)) + if (!locals_match(table, i, file_sym, sym_list, 90 /* match_pct */)) continue; if (lookup_table_file_sym) ERROR("found duplicate matches for %s local symbols in %s symbol table",