]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
perf symbol: Add setters for bitfields sharing a byte to avoid concurrent update...
authorIan Rogers <irogers@google.com>
Tue, 2 Jun 2026 15:25:15 +0000 (08:25 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Wed, 3 Jun 2026 19:53:45 +0000 (16:53 -0300)
A problem with putting bitfields into struct symbol is that other bits in
the symbol could be updated concurrently and only one update to the
underlying storage unit happen, leading to lost updates.

To avoid this, use atomics to atomically read or set part of 16-bits
of flags in the symbol. Add accessors to simplify this.

The idle value has 3 values in preparation for a later change that
will lazily update it.

Assisted-by: Gemini:gemini-3.1-pro-preview
Signed-off-by: Ian Rogers <irogers@google.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Cc: Alexander Gordeev <agordeev@linux.ibm.com>
Cc: Heiko Carstens <hca@linux.ibm.com>
Cc: Honglei Wang <jameshongleiwang@126.com>
Cc: Jan Polensky <japo@linux.ibm.com>
Cc: Sumanth Korikkar <sumanthk@linux.ibm.com>
Cc: Thomas Richter <tmricht@linux.ibm.com>
Cc: Vasily Gorbik <gor@linux.ibm.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
26 files changed:
tools/perf/builtin-inject.c
tools/perf/builtin-kwork.c
tools/perf/builtin-report.c
tools/perf/builtin-sched.c
tools/perf/builtin-top.c
tools/perf/tests/symbols.c
tools/perf/tests/vmlinux-kallsyms.c
tools/perf/ui/browsers/annotate.c
tools/perf/ui/browsers/map.c
tools/perf/util/annotate.c
tools/perf/util/auxtrace.c
tools/perf/util/callchain.c
tools/perf/util/dlfilter.c
tools/perf/util/evsel_fprintf.c
tools/perf/util/intel-pt.c
tools/perf/util/libdw.c
tools/perf/util/machine.c
tools/perf/util/probe-event.c
tools/perf/util/scripting-engines/trace-event-perl.c
tools/perf/util/scripting-engines/trace-event-python.c
tools/perf/util/sort.c
tools/perf/util/srcline.c
tools/perf/util/symbol-elf.c
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/symbol_fprintf.c

index d8cb1f562f690ce40d32827c487534f9b68c0f9f..75ffe31d03fea42c78a53c5d279273ec868b56f4 100644 (file)
@@ -549,13 +549,11 @@ static int perf_event__convert_sample_callchain(const struct perf_tool *tool,
 
        node = cursor->first;
        for (k = 0; k < cursor->nr && i < PERF_MAX_STACK_DEPTH; k++) {
-               if (machine->single_address_space &&
-                   machine__kernel_ip(machine, node->ip))
-                       /* kernel IPs were added already */;
-               else if (node->ms.sym && node->ms.sym->inlined)
-                       /* we can't handle inlined callchains */;
-               else
+               if (!(machine->single_address_space &&
+                     machine__kernel_ip(machine, node->ip)) &&
+                   !(node->ms.sym && symbol__inlined(node->ms.sym))) {
                        inject->raw_callchain->ips[i++] = node->ip;
+               }
 
                node = node->next;
        }
index 110de3507d48160c9fb3f886aa5d9a7aa1923e71..7b61168e01e9d4614a7f6946283241a4dd2ebe04 100644 (file)
@@ -770,7 +770,7 @@ static void timehist_save_callchain(struct perf_kwork *kwork,
                if (sym) {
                        if (!strcmp(sym->name, "__softirqentry_text_start") ||
                            !strcmp(sym->name, "__do_softirq"))
-                               sym->ignore = 1;
+                               symbol__set_ignore(sym, true);
                }
 
                callchain_cursor_advance(cursor);
index cd052aa78132b65faf3641f4985693237b5f0850..6f044c3df8937dc564b2704907fdb698381e3bc2 100644 (file)
@@ -752,7 +752,7 @@ static int hists__resort_cb(struct hist_entry *he, void *arg)
        struct report *rep = arg;
        struct symbol *sym = he->ms.sym;
 
-       if (rep->symbol_ipc && sym && !sym->annotate2) {
+       if (rep->symbol_ipc && sym && !symbol__is_annotate2(sym)) {
                struct evsel *evsel = hists_to_evsel(he->hists);
 
                symbol__annotate2(&he->ms, evsel, NULL);
index 81833d169470582bd2e373e1323144a22b265246..4de2baf03c5036dc93fa43d2f02d544d895e7a3b 100644 (file)
@@ -2387,7 +2387,7 @@ static void save_task_callchain(struct perf_sched *sched,
                        if (!strcmp(sym->name, "schedule") ||
                            !strcmp(sym->name, "__schedule") ||
                            !strcmp(sym->name, "preempt_schedule"))
-                               sym->ignore = 1;
+                               symbol__set_ignore(sym, true);
                }
 
                callchain_cursor_advance(cursor);
@@ -3048,7 +3048,7 @@ static size_t callchain__fprintf_folded(FILE *fp, struct callchain_node *node)
        list_for_each_entry(chain, &node->val, list) {
                if (chain->ip >= PERF_CONTEXT_MAX)
                        continue;
-               if (chain->ms.sym && chain->ms.sym->ignore)
+               if (chain->ms.sym && symbol__ignore(chain->ms.sym))
                        continue;
                ret += fprintf(fp, "%s%s", first ? "" : sep,
                               callchain_list__sym_name(chain, bf, sizeof(bf),
index c8474f7ac65809a1c85297ebbcc17f453874f500..1211401616ee33b8c0aa711b1371e1473a757acc 100644 (file)
@@ -186,8 +186,8 @@ static void ui__warn_map_erange(struct map *map, struct symbol *sym, u64 ip)
                    "Please report to linux-kernel@vger.kernel.org\n",
                    ip, dso__long_name(dso), dso__symtab_origin(dso),
                    map__start(map), map__end(map), sym->start, sym->end,
-                   sym->binding == STB_GLOBAL ? 'g' :
-                   sym->binding == STB_LOCAL  ? 'l' : 'w', sym->name,
+                   symbol__binding(sym) == STB_GLOBAL ? 'g' :
+                   symbol__binding(sym) == STB_LOCAL  ? 'l' : 'w', sym->name,
                    err ? "[unknown]" : uts.machine,
                    err ? "[unknown]" : uts.release, perf_version_string);
        if (use_browser <= 0)
@@ -828,7 +828,8 @@ static void perf_event__process_sample(const struct perf_tool *tool,
                }
        }
 
-       if (al.sym == NULL || !al.sym->idle) {
+       if (al.sym == NULL ||
+           !symbol__is_idle(al.sym, al.map ? map__dso(al.map) : NULL, machine->env)) {
                struct hists *hists = evsel__hists(sample->evsel);
                struct hist_entry_iter iter = {
                        .sample         = sample,
index f4ffe5804f401f5d239c1170e4088594eee8a727..c09e04f36035a50e0de56a24ab2d56bb37e688d8 100644 (file)
@@ -125,7 +125,7 @@ static int test_dso(struct dso *dso)
        for (nd = rb_first_cached(dso__symbols(dso)); nd; nd = rb_next(nd)) {
                struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
 
-               if (sym->type != STT_FUNC && sym->type != STT_GNU_IFUNC)
+               if (symbol__type(sym) != STT_FUNC && symbol__type(sym) != STT_GNU_IFUNC)
                        continue;
 
                /* Check for overlapping function symbols */
index 524d46478364d9dd9e2c4d8e59c1a66480595991..7409abe4aa3692ea1a68ed63827b24f84be9a601 100644 (file)
@@ -346,7 +346,7 @@ next_pair:
                         * such as __indirect_thunk_end.
                         */
                        continue;
-               } else if (is_ignored_symbol(sym->name, sym->type)) {
+               } else if (is_ignored_symbol(sym->name, symbol__type(sym))) {
                        /*
                         * Ignore hidden symbols, see scripts/kallsyms.c for the details
                         */
index ea17e6d29a7e49690d55800784e6de8f4533b865..e220c4dfc8819c308c0e5bd08d33cb02c6516036 100644 (file)
@@ -1185,7 +1185,7 @@ int __hist_entry__tui_annotate(struct hist_entry *he, struct map_symbol *ms,
        if (dso__annotate_warned(dso))
                return -1;
 
-       if (not_annotated || !sym->annotate2) {
+       if (not_annotated || !symbol__is_annotate2(sym)) {
                err = symbol__annotate2(ms, evsel, &browser.arch);
                if (err) {
                        annotate_browser__symbol_annotate_error(&browser, err);
index c61ba3174a240fa8199b2a4149fda53543be3ae6..075a575cdc5d4a9071c358f7eeb667ac289016de 100644 (file)
@@ -32,8 +32,8 @@ static void map_browser__write(struct ui_browser *browser, void *nd, int row)
        ui_browser__set_percent_color(browser, 0, current_entry);
        ui_browser__printf(browser, "%*" PRIx64 " %*" PRIx64 " %c ",
                           mb->addrlen, sym->start, mb->addrlen, sym->end,
-                          sym->binding == STB_GLOBAL ? 'g' :
-                               sym->binding == STB_LOCAL  ? 'l' : 'w');
+                          symbol__binding(sym) == STB_GLOBAL ? 'g' :
+                               symbol__binding(sym) == STB_LOCAL  ? 'l' : 'w');
        width = browser->width - ((mb->addrlen * 2) + 4);
        if (width > 0)
                ui_browser__write_nstring(browser, sym->name, width);
index 470569745abef4f544b20807b527f09b48186201..02505222d8c2d4344f2374a5723451cb6b5b5ce0 100644 (file)
@@ -236,7 +236,8 @@ static int __symbol__inc_addr_samples(struct map_symbol *ms,
        h = annotated_source__histogram(src, evsel);
        if (h == NULL) {
                pr_debug("%s(%d): ENOMEM! sym->name=%s, start=%#" PRIx64 ", addr=%#" PRIx64 ", end=%#" PRIx64 ", func: %d\n",
-                        __func__, __LINE__, sym->name, sym->start, addr, sym->end, sym->type == STT_FUNC);
+                        __func__, __LINE__, sym->name, sym->start, addr, sym->end,
+                        symbol__type(sym) == STT_FUNC);
                return -ENOMEM;
        }
 
@@ -2223,7 +2224,7 @@ int symbol__annotate2(struct map_symbol *ms, struct evsel *evsel,
 
        annotation__init_column_widths(notes, sym);
        annotation__update_column_widths(notes);
-       sym->annotate2 = 1;
+       symbol__set_annotate2(sym, true);
 
        return 0;
 }
index fcf564e0d777f8f910168cdef503c26337958137..5f4aa1701aef649a6872074e7d9594285c48161e 100644 (file)
@@ -2694,7 +2694,7 @@ static bool dso_sym_match(struct symbol *sym, const char *name, int *cnt,
 {
        /* Same name, and global or the n'th found or any */
        return !arch__compare_symbol_names(name, sym->name) &&
-              ((!idx && sym->binding == STB_GLOBAL) ||
+              ((!idx && symbol__binding(sym) == STB_GLOBAL) ||
                (idx > 0 && ++*cnt == idx) ||
                idx < 0);
 }
@@ -2712,8 +2712,8 @@ static void print_duplicate_syms(struct dso *dso, const char *sym_name)
                if (dso_sym_match(sym, sym_name, &cnt, -1)) {
                        pr_err("#%d\t0x%"PRIx64"\t%c\t%s\n",
                               ++cnt, sym->start,
-                              sym->binding == STB_GLOBAL ? 'g' :
-                              sym->binding == STB_LOCAL  ? 'l' : 'w',
+                              symbol__binding(sym) == STB_GLOBAL ? 'g' :
+                              symbol__binding(sym) == STB_LOCAL  ? 'l' : 'w',
                               sym->name);
                        near = true;
                } else if (near) {
index 5c2282051e394ba5261bcbc4d1ecf91faee4e5f9..8981ae879ebb887c4aa08b4e7105030f319e7f77 100644 (file)
@@ -801,7 +801,7 @@ static enum match_result match_chain(struct callchain_cursor_node *node,
                         * symbol start. Otherwise do a faster comparison based
                         * on the symbol start address.
                         */
-                       if (cnode->ms.sym->inlined || node->ms.sym->inlined) {
+                       if (symbol__inlined(cnode->ms.sym) || symbol__inlined(node->ms.sym)) {
                                match = match_chain_strings(cnode->ms.sym->name,
                                                            node->ms.sym->name);
                                if (match != MATCH_ERROR)
@@ -1245,7 +1245,7 @@ char *callchain_list__sym_name(struct callchain_list *cl,
        int printed;
 
        if (cl->ms.sym) {
-               const char *inlined = cl->ms.sym->inlined ? " (inlined)" : "";
+               const char *inlined = symbol__inlined(cl->ms.sym) ? " (inlined)" : "";
 
                if (show_srcline && cl->srcline)
                        printed = scnprintf(bf, bfsize, "%s %s%s",
index dc31b5e7149e76c05c80e468f47ab0ab24d49ab8..e11e144af62bb979f4bf2c8fae1a4d1c82ef977a 100644 (file)
@@ -56,7 +56,7 @@ static void al_to_d_al(struct addr_location *al, struct perf_dlfilter_al *d_al)
                        d_al->symoff = al->addr - map__start(al->map) - sym->start;
                else
                        d_al->symoff = 0;
-               d_al->sym_binding = sym->binding;
+               d_al->sym_binding = symbol__binding(sym);
        } else {
                d_al->sym = NULL;
                d_al->sym_start = 0;
index 5521d00bff2c0f21edd89f1ad9dc14d8bfb327ed..0f7a25500a447ee1f6edacd86180e3e403bccfaa 100644 (file)
@@ -146,7 +146,7 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
                        sym = node->ms.sym;
                        map = node->ms.map;
 
-                       if (sym && sym->ignore && print_skip_ignored)
+                       if (sym && symbol__ignore(sym) && print_skip_ignored)
                                goto next;
 
                        printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " ");
@@ -182,7 +182,7 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
                                addr_location__exit(&node_al);
                        }
 
-                       if (print_dso && (!sym || !sym->inlined))
+                       if (print_dso && (!sym || !symbol__inlined(sym)))
                                printed += map__fprintf_dsoname_dsoff(map, print_dsoff, addr, fp);
 
                        if (print_srcline) {
@@ -192,7 +192,7 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
                                        printed += map__fprintf_srcline(map, addr, "\n  ", fp);
                        }
 
-                       if (sym && sym->inlined)
+                       if (sym && symbol__inlined(sym))
                                printed += fprintf(fp, " (inlined)");
 
                        if (!print_oneline)
index b8add2b2003378faccc61f1482cb24e7eecd5d5f..56a9e439f5f8fe64045e36a321c220b39328fb48 100644 (file)
@@ -3000,7 +3000,7 @@ static u64 intel_pt_switch_ip(struct intel_pt *pt, u64 *ptss_ip)
        start = dso__first_symbol(map__dso(map));
 
        for (sym = start; sym; sym = dso__next_symbol(sym)) {
-               if (sym->binding == STB_GLOBAL &&
+               if (symbol__binding(sym) == STB_GLOBAL &&
                    !strcmp(sym->name, "__switch_to")) {
                        ip = map__unmap_ip(map, sym->start);
                        if (ip >= map__start(map) && ip < map__end(map)) {
index 84713b2a7ad5da3932b13ddcb474150179ca54e0..d5d2958902c0a27c6155aafc7e92061760af1ce2 100644 (file)
@@ -130,7 +130,7 @@ static int libdw_a2l_cb(Dwarf_Die *die, void *_args)
        return 0;
 
 abort_delete_sym:
-       if (inline_sym->inlined)
+       if (symbol__inlined(inline_sym))
                symbol__delete(inline_sym);
 abort_enomem:
        args->err = -ENOMEM;
index 47be7a44a5f7b1991ac2367f4a7b0c5129e91f0e..da1ad58758afd9d97c66acbca6623516c9c0491e 100644 (file)
@@ -1095,7 +1095,7 @@ static u64 find_entry_trampoline(struct dso *dso)
        unsigned int i;
 
        for (; sym; sym = dso__next_symbol(sym)) {
-               if (sym->binding != STB_GLOBAL)
+               if (symbol__binding(sym) != STB_GLOBAL)
                        continue;
                for (i = 0; i < ARRAY_SIZE(syms); i++) {
                        if (!strcmp(sym->name, syms[i]))
index 34b4badd2c14ade0ba8d9011c0451e9cedb9f909..11ae4a09412c9bd921685e4556d21a3cdf10c891 100644 (file)
@@ -416,7 +416,7 @@ static int find_alternative_probe_point(struct debuginfo *dinfo,
        map__for_each_symbol_by_name(map, pp->function, sym, idx) {
                if (uprobes) {
                        address = sym->start;
-                       if (sym->type == STT_GNU_IFUNC)
+                       if (symbol__type(sym) == STT_GNU_IFUNC)
                                pr_warning("Warning: The probe function (%s) is a GNU indirect function.\n"
                                           "Consider identifying the final function used at run time and set the probe directly on that.\n",
                                           pp->function);
@@ -3189,7 +3189,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
        for (j = 0; j < num_matched_functions; j++) {
                sym = syms[j];
 
-               if (sym->type != STT_FUNC)
+               if (symbol__type(sym) != STT_FUNC)
                        continue;
 
                /* There can be duplicated symbols in the map */
index 7a18ea4b7d50196518a6263bd2919321d54e3014..410dc4cd06009b5d2e33d36bcaa1816cd6860dd9 100644 (file)
@@ -303,7 +303,7 @@ static SV *perl_process_callchain(struct perf_sample *sample,
                        }
                        if (!hv_stores(sym, "start",   newSVuv(node->ms.sym->start)) ||
                            !hv_stores(sym, "end",     newSVuv(node->ms.sym->end)) ||
-                           !hv_stores(sym, "binding", newSVuv(node->ms.sym->binding)) ||
+                           !hv_stores(sym, "binding", newSVuv(symbol__binding(node->ms.sym))) ||
                            !hv_stores(sym, "name",    newSVpvn(node->ms.sym->name,
                                                                node->ms.sym->namelen)) ||
                            !hv_stores(elem, "sym",    newRV_noinc((SV*)sym))) {
index cee1f32d70225cc73bd9e0e1c3a0fd18bf852bd0..8f832ae316ca7ea39297504660c5941df6690afe 100644 (file)
@@ -436,7 +436,7 @@ static PyObject *python_process_callchain(struct perf_sample *sample,
                        pydict_set_item_string_decref(pysym, "end",
                                        PyLong_FromUnsignedLongLong(node->ms.sym->end));
                        pydict_set_item_string_decref(pysym, "binding",
-                                       _PyLong_FromLong(node->ms.sym->binding));
+                                       _PyLong_FromLong(symbol__binding(node->ms.sym)));
                        pydict_set_item_string_decref(pysym, "name",
                                        _PyUnicode_FromStringAndSize(node->ms.sym->name,
                                                        node->ms.sym->namelen));
@@ -1270,7 +1270,7 @@ static int python_export_symbol(struct db_export *dbe, struct symbol *sym,
        tuple_set_d64(t, 1, dso__db_id(dso));
        tuple_set_d64(t, 2, sym->start);
        tuple_set_d64(t, 3, sym->end);
-       tuple_set_s32(t, 4, sym->binding);
+       tuple_set_s32(t, 4, symbol__binding(sym));
        tuple_set_string(t, 5, sym->name);
 
        call_object(tables->symbol_handler, t, "symbol_table");
index 90bc4a31bb554c1774cdc9c55faa570479112604..005e7d85dc4a593b2f8999bf1efb5824227fc820 100644 (file)
@@ -469,7 +469,7 @@ int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
        if (sym_l == sym_r)
                return 0;
 
-       if (sym_l->inlined || sym_r->inlined) {
+       if (symbol__inlined(sym_l) || symbol__inlined(sym_r)) {
                int ret = strcmp(sym_l->name, sym_r->name);
 
                if (ret)
@@ -536,7 +536,7 @@ static int _hist_entry__sym_snprintf(struct map_symbol *ms,
 
        ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
        if (sym && map) {
-               if (sym->type == STT_OBJECT) {
+               if (symbol__type(sym) == STT_OBJECT) {
                        ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
                        ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
                                        ip - map__unmap_ip(map, sym->start));
@@ -544,7 +544,7 @@ static int _hist_entry__sym_snprintf(struct map_symbol *ms,
                        ret += repsep_snprintf(bf + ret, size - ret, "%.*s",
                                               width - ret,
                                               sym->name);
-                       if (sym->inlined)
+                       if (symbol__inlined(sym))
                                ret += repsep_snprintf(bf + ret, size - ret,
                                                       " (inlined)");
                }
@@ -1483,7 +1483,7 @@ static int _hist_entry__addr_snprintf(struct map_symbol *ms,
 
        ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
        if (sym && map) {
-               if (sym->type == STT_OBJECT) {
+               if (symbol__type(sym) == STT_OBJECT) {
                        ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
                        ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
                                        ip - map__unmap_ip(map, sym->start));
index 62884428fb5a044108f394c0935e9e8efcfd41cb..b082178c279b6b95c1f46d82d6716a66f36ceb68 100644 (file)
@@ -113,16 +113,16 @@ struct symbol *new_inline_sym(struct dso *dso,
                /* ensure that we don't alias an inlined symbol, which could
                 * lead to double frees in inline_node__delete
                 */
-               assert(!base_sym->inlined);
+               assert(!symbol__inlined(base_sym));
        } else {
                /* create a fake symbol for the inline frame */
                inline_sym = symbol__new(base_sym ? base_sym->start : 0,
                                         base_sym ? (base_sym->end - base_sym->start) : 0,
-                                        base_sym ? base_sym->binding : 0,
-                                        base_sym ? base_sym->type : 0,
+                                        base_sym ? symbol__binding(base_sym) : 0,
+                                        base_sym ? symbol__type(base_sym) : 0,
                                         funcname);
                if (inline_sym)
-                       inline_sym->inlined = 1;
+                       symbol__set_inlined(inline_sym, true);
        }
 
        free(demangled);
@@ -440,7 +440,7 @@ void inline_node__clear_frames(struct inline_node *node)
                list_del_init(&ilist->list);
                zfree_srcline(&ilist->srcline);
                /* only the inlined symbols are owned by the list */
-               if (ilist->symbol && ilist->symbol->inlined)
+               if (ilist->symbol && symbol__inlined(ilist->symbol))
                        symbol__delete(ilist->symbol);
                free(ilist);
        }
index 77e6dcba8fda17fdc8569b9e41f0dd22202d5276..c5ed5e0519764239d2d38becef52f4687e3a6246 100644 (file)
@@ -350,7 +350,8 @@ static bool get_ifunc_name(Elf *elf, struct dso *dso, GElf_Ehdr *ehdr,
        sym = dso__find_symbol_nocache(dso, addr);
 
        /* Expecting the address to be an IFUNC or IFUNC alias */
-       if (!sym || sym->start != addr || (sym->type != STT_GNU_IFUNC && !sym->ifunc_alias))
+       if (!sym || sym->start != addr ||
+           (symbol__type(sym) != STT_GNU_IFUNC && !symbol__ifunc_alias(sym)))
                return false;
 
        snprintf(buf, buf_sz, "%s@plt", sym->name);
index 077d19af5240871e8bc287d25500ba8206cf0d80..ddd3106b03b167742dacac5a4db4a9de988679c4 100644 (file)
@@ -50,7 +50,7 @@
 
 static int dso__load_kernel_sym(struct dso *dso, struct map *map);
 static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map);
-static bool symbol__is_idle(const char *name);
+static bool symbol__compute_is_idle(const char *name);
 
 int vmlinux_path__nr_entries;
 char **vmlinux_path;
@@ -163,24 +163,24 @@ static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
        else if ((a == 0) && (b > 0))
                return SYMBOL_B;
 
-       if (syma->type != symb->type) {
-               if (syma->type == STT_NOTYPE)
+       if (symbol__type(syma) != symbol__type(symb)) {
+               if (symbol__type(syma) == STT_NOTYPE)
                        return SYMBOL_B;
-               if (symb->type == STT_NOTYPE)
+               if (symbol__type(symb) == STT_NOTYPE)
                        return SYMBOL_A;
        }
 
        /* Prefer a non weak symbol over a weak one */
-       a = syma->binding == STB_WEAK;
-       b = symb->binding == STB_WEAK;
+       a = symbol__binding(syma) == STB_WEAK;
+       b = symbol__binding(symb) == STB_WEAK;
        if (b && !a)
                return SYMBOL_A;
        if (a && !b)
                return SYMBOL_B;
 
        /* Prefer a global symbol over a non global one */
-       a = syma->binding == STB_GLOBAL;
-       b = symb->binding == STB_GLOBAL;
+       a = symbol__binding(syma) == STB_GLOBAL;
+       b = symbol__binding(symb) == STB_GLOBAL;
        if (a && !b)
                return SYMBOL_A;
        if (b && !a)
@@ -227,14 +227,14 @@ again:
                        continue;
 
                if (choose_best_symbol(curr, next) == SYMBOL_A) {
-                       if (next->type == STT_GNU_IFUNC)
-                               curr->ifunc_alias = true;
+                       if (symbol__type(next) == STT_GNU_IFUNC)
+                               symbol__set_ifunc_alias(curr, true);
                        rb_erase_cached(&next->rb_node, symbols);
                        symbol__delete(next);
                        goto again;
                } else {
-                       if (curr->type == STT_GNU_IFUNC)
-                               next->ifunc_alias = true;
+                       if (symbol__type(curr) == STT_GNU_IFUNC)
+                               symbol__set_ifunc_alias(next, true);
                        nd = rb_next(&curr->rb_node);
                        rb_erase_cached(&curr->rb_node, symbols);
                        symbol__delete(curr);
@@ -322,8 +322,8 @@ struct symbol *symbol__new(u64 start, u64 len, u8 binding, u8 type, const char *
 
        sym->start   = start;
        sym->end     = len ? start + len : start;
-       sym->type    = type;
-       sym->binding = binding;
+       atomic_init(&sym->flags, (type << SYMBOL_FLAG_TYPE_SHIFT) |
+                                (binding << SYMBOL_FLAG_BINDING_SHIFT));
        sym->namelen = namelen - 1;
 
        pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n",
@@ -345,6 +345,49 @@ void symbol__delete(struct symbol *sym)
        free(((void *)sym) - symbol_conf.priv_size);
 }
 
+void symbol__set_ignore(struct symbol *sym, bool ignore)
+{
+       if (ignore)
+               atomic_fetch_or(&sym->flags, SYMBOL_FLAG_IGNORE);
+       else
+               atomic_fetch_and(&sym->flags, ~SYMBOL_FLAG_IGNORE);
+}
+
+void symbol__set_annotate2(struct symbol *sym, bool annotate2)
+{
+       if (annotate2)
+               atomic_fetch_or(&sym->flags, SYMBOL_FLAG_ANNOTATE2);
+       else
+               atomic_fetch_and(&sym->flags, ~SYMBOL_FLAG_ANNOTATE2);
+}
+
+void symbol__set_inlined(struct symbol *sym, bool inlined)
+{
+       if (inlined)
+               atomic_fetch_or(&sym->flags, SYMBOL_FLAG_INLINED);
+       else
+               atomic_fetch_and(&sym->flags, ~SYMBOL_FLAG_INLINED);
+}
+
+void symbol__set_ifunc_alias(struct symbol *sym, bool ifunc_alias)
+{
+       if (ifunc_alias)
+               atomic_fetch_or(&sym->flags, SYMBOL_FLAG_IFUNC_ALIAS);
+       else
+               atomic_fetch_and(&sym->flags, ~SYMBOL_FLAG_IFUNC_ALIAS);
+}
+
+static void symbol__set_idle(struct symbol *sym, bool idle)
+{
+       uint16_t old_flags = atomic_load(&sym->flags);
+       uint16_t new_flags;
+       uint16_t idle_val = idle ? SYMBOL_IDLE__IDLE : SYMBOL_IDLE__NOT_IDLE;
+
+       do {
+               new_flags = old_flags & ~SYMBOL_FLAG_IDLE_MASK;
+               new_flags |= (idle_val << SYMBOL_FLAG_IDLE_SHIFT);
+       } while (!atomic_compare_exchange_weak(&sym->flags, &old_flags, new_flags));
+}
 void symbols__delete(struct rb_root_cached *symbols)
 {
        struct symbol *pos;
@@ -375,7 +418,7 @@ void __symbols__insert(struct rb_root_cached *symbols,
                 */
                if (name[0] == '.')
                        name++;
-               sym->idle = symbol__is_idle(name);
+               symbol__set_idle(sym, symbol__compute_is_idle(name));
        }
 
        while (*p != NULL) {
@@ -717,11 +760,21 @@ out:
        return err;
 }
 
+bool symbol__is_idle(struct symbol *sym,
+                    const struct dso *dso __maybe_unused,
+                    struct perf_env *env __maybe_unused)
+{
+       uint16_t flags = atomic_load_explicit(&sym->flags, memory_order_relaxed);
+       uint16_t idle_val = (flags & SYMBOL_FLAG_IDLE_MASK) >> SYMBOL_FLAG_IDLE_SHIFT;
+
+       return idle_val == SYMBOL_IDLE__IDLE;
+}
+
 /*
  * These are symbols in the kernel image, so make sure that
  * sym is from a kernel DSO.
  */
-static bool symbol__is_idle(const char *name)
+static bool symbol__compute_is_idle(const char *name)
 {
        const char * const idle_symbols[] = {
                "acpi_idle_do_entry",
@@ -2492,6 +2545,7 @@ void symbol__exit(void)
 {
        if (!symbol_conf.initialized)
                return;
+
        strlist__delete(symbol_conf.bt_stop_list);
        strlist__delete(symbol_conf.sym_list);
        strlist__delete(symbol_conf.dso_list);
index 95592779eb77cecdb11e56907c09df8336b6e620..16a27074a474f52958d1d9c3f203fcf0c394ec39 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/refcount.h>
 #include <stdbool.h>
 #include <stdint.h>
+#include <stdatomic.h>
 #include <linux/list.h>
 #include <linux/rbtree.h>
 #include <stdio.h>
@@ -27,6 +28,7 @@ struct map;
 struct maps;
 struct option;
 struct build_id;
+struct perf_env;
 
 /*
  * Ignore kernel mapping symbols, matching kernel is_mapping_symbol() logic.
@@ -58,6 +60,23 @@ Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
                             GElf_Shdr *shp, const char *name, size_t *idx);
 #endif
 
+enum symbol_idle_kind {
+       SYMBOL_IDLE__UNKNOWN = 0,
+       SYMBOL_IDLE__NOT_IDLE = 1,
+       SYMBOL_IDLE__IDLE = 2,
+};
+
+#define SYMBOL_FLAG_TYPE_SHIFT      0
+#define SYMBOL_FLAG_TYPE_MASK       (0xF << SYMBOL_FLAG_TYPE_SHIFT)
+#define SYMBOL_FLAG_BINDING_SHIFT   4
+#define SYMBOL_FLAG_BINDING_MASK    (0xF << SYMBOL_FLAG_BINDING_SHIFT)
+#define SYMBOL_FLAG_IDLE_SHIFT      8
+#define SYMBOL_FLAG_IDLE_MASK       (0x3 << SYMBOL_FLAG_IDLE_SHIFT)
+#define SYMBOL_FLAG_IGNORE          (1 << 10)
+#define SYMBOL_FLAG_INLINED         (1 << 11)
+#define SYMBOL_FLAG_ANNOTATE2       (1 << 12)
+#define SYMBOL_FLAG_IFUNC_ALIAS     (1 << 13)
+
 /**
  * A symtab entry. When allocated this may be preceded by an annotation (see
  * symbol__annotation) and/or a browser_index (see symbol__browser_index).
@@ -69,20 +88,7 @@ struct symbol {
        u64             end;
        /** Length of the string name. */
        u16             namelen;
-       /** ELF symbol type as defined for st_info. E.g STT_OBJECT or STT_FUNC. */
-       u8              type:4;
-       /** ELF binding type as defined for st_info. E.g. STB_WEAK or STB_GLOBAL. */
-       u8              binding:4;
-       /** Set true for kernel symbols of idle routines. */
-       u8              idle:1;
-       /** Resolvable but tools ignore it (e.g. idle routines). */
-       u8              ignore:1;
-       /** Symbol for an inlined function. */
-       u8              inlined:1;
-       /** Has symbol__annotate2 been performed. */
-       u8              annotate2:1;
-       /** Symbol is an alias of an STT_GNU_IFUNC */
-       u8              ifunc_alias:1;
+       _Atomic uint16_t flags;
        /** Architecture specific. Unused except on PPC where it holds st_other. */
        u8              arch_sym;
        /** The name of length namelen associated with the symbol. */
@@ -92,6 +98,49 @@ struct symbol {
 void symbol__delete(struct symbol *sym);
 void symbols__delete(struct rb_root_cached *symbols);
 
+static inline u8 symbol__type(const struct symbol *sym)
+{
+       return (atomic_load_explicit(&sym->flags, memory_order_relaxed) &
+               SYMBOL_FLAG_TYPE_MASK) >> SYMBOL_FLAG_TYPE_SHIFT;
+}
+
+static inline u8 symbol__binding(const struct symbol *sym)
+{
+       return (atomic_load_explicit(&sym->flags, memory_order_relaxed) &
+               SYMBOL_FLAG_BINDING_MASK) >> SYMBOL_FLAG_BINDING_SHIFT;
+}
+
+static inline bool symbol__ignore(const struct symbol *sym)
+{
+       return (atomic_load_explicit(&sym->flags, memory_order_relaxed) &
+               SYMBOL_FLAG_IGNORE) != 0;
+}
+
+static inline bool symbol__inlined(const struct symbol *sym)
+{
+       return (atomic_load_explicit(&sym->flags, memory_order_relaxed) &
+               SYMBOL_FLAG_INLINED) != 0;
+}
+
+static inline bool symbol__is_annotate2(const struct symbol *sym)
+{
+       return (atomic_load_explicit(&sym->flags, memory_order_relaxed) &
+               SYMBOL_FLAG_ANNOTATE2) != 0;
+}
+
+static inline bool symbol__ifunc_alias(const struct symbol *sym)
+{
+       return (atomic_load_explicit(&sym->flags, memory_order_relaxed) &
+               SYMBOL_FLAG_IFUNC_ALIAS) != 0;
+}
+
+bool symbol__is_idle(struct symbol *sym, const struct dso *dso, struct perf_env *env);
+
+void symbol__set_ignore(struct symbol *sym, bool ignore);
+void symbol__set_annotate2(struct symbol *sym, bool annotate2);
+void symbol__set_inlined(struct symbol *sym, bool inlined);
+void symbol__set_ifunc_alias(struct symbol *sym, bool ifunc_alias);
+
 /* symbols__for_each_entry - iterate over symbols (rb_root)
  *
  * @symbols: the rb_root of symbols
@@ -169,7 +218,6 @@ int filename__read_debuglink(const char *filename, char *debuglink,
                             size_t size);
 bool filename__has_section(const char *filename, const char *sec);
 
-struct perf_env;
 int symbol__init(struct perf_env *env);
 void symbol__exit(void);
 void symbol__elf_init(void);
index 53e1af4ed9ac2a6d05b54262530ac6a8710e50c9..4dc8d5761f52275ded761140e03e537cfc743791 100644 (file)
@@ -11,8 +11,8 @@ size_t symbol__fprintf(struct symbol *sym, FILE *fp)
 {
        return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n",
                       sym->start, sym->end,
-                      sym->binding == STB_GLOBAL ? 'g' :
-                      sym->binding == STB_LOCAL  ? 'l' : 'w',
+                      symbol__binding(sym) == STB_GLOBAL ? 'g' :
+                      symbol__binding(sym) == STB_LOCAL  ? 'l' : 'w',
                       sym->name);
 }