diff options
Diffstat (limited to 'tools/perf')
29 files changed, 515 insertions, 50 deletions
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 3519a0139026..c0a208f9b67b 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -38,7 +38,7 @@ ifneq ($(NO_SYSCALL_TABLE),1) NO_SYSCALL_TABLE := 0 endif else - ifeq ($(SRCARCH),$(filter $(SRCARCH),powerpc arm64 s390 mips)) + ifeq ($(SRCARCH),$(filter $(SRCARCH),powerpc arm64 s390 mips loongarch)) NO_SYSCALL_TABLE := 0 endif endif @@ -80,6 +80,12 @@ ifeq ($(SRCARCH),arm64) LIBUNWIND_LIBS = -lunwind -lunwind-aarch64 endif +ifeq ($(SRCARCH),loongarch) + NO_PERF_REGS := 0 + CFLAGS += -I$(OUTPUT)arch/loongarch/include/generated + LIBUNWIND_LIBS = -lunwind -lunwind-loongarch64 +endif + ifeq ($(SRCARCH),riscv) NO_PERF_REGS := 0 endif @@ -107,7 +113,7 @@ endif # Disable it on all other architectures in case libdw unwind # support is detected in system. Add supported architectures # to the check. -ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm arm64 powerpc s390 csky riscv)) +ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm arm64 powerpc s390 csky riscv loongarch)) NO_LIBDW_DWARF_UNWIND := 1 endif @@ -129,7 +135,7 @@ endef ifdef LIBUNWIND_DIR LIBUNWIND_CFLAGS = -I$(LIBUNWIND_DIR)/include LIBUNWIND_LDFLAGS = -L$(LIBUNWIND_DIR)/lib - LIBUNWIND_ARCHS = x86 x86_64 arm aarch64 debug-frame-arm debug-frame-aarch64 + LIBUNWIND_ARCHS = x86 x86_64 arm aarch64 debug-frame-arm debug-frame-aarch64 loongarch $(foreach libunwind_arch,$(LIBUNWIND_ARCHS),$(call libunwind_arch_set_flags,$(libunwind_arch))) endif diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c index 59dd875fd5e4..cfe63dfab03a 100644 --- a/tools/perf/arch/common.c +++ b/tools/perf/arch/common.c @@ -51,9 +51,7 @@ const char *const s390_triplets[] = { const char *const sh_triplets[] = { "sh-unknown-linux-gnu-", - "sh64-unknown-linux-gnu-", "sh-linux-gnu-", - "sh64-linux-gnu-", NULL }; diff --git a/tools/perf/arch/loongarch/Build b/tools/perf/arch/loongarch/Build new file mode 100644 index 000000000000..e4e5f33c84d8 --- /dev/null +++ b/tools/perf/arch/loongarch/Build @@ -0,0 +1 @@ +perf-y += util/ diff --git a/tools/perf/arch/loongarch/Makefile b/tools/perf/arch/loongarch/Makefile new file mode 100644 index 000000000000..c392e7af4743 --- /dev/null +++ b/tools/perf/arch/loongarch/Makefile @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0 +ifndef NO_DWARF +PERF_HAVE_DWARF_REGS := 1 +endif +PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1 +PERF_HAVE_JITDUMP := 1 + +# +# Syscall table generation for perf +# + +out := $(OUTPUT)arch/loongarch/include/generated/asm +header := $(out)/syscalls.c +incpath := $(srctree)/tools +sysdef := $(srctree)/tools/arch/loongarch/include/uapi/asm/unistd.h +sysprf := $(srctree)/tools/perf/arch/loongarch/entry/syscalls/ +systbl := $(sysprf)/mksyscalltbl + +# Create output directory if not already present +_dummy := $(shell [ -d '$(out)' ] || mkdir -p '$(out)') + +$(header): $(sysdef) $(systbl) + $(Q)$(SHELL) '$(systbl)' '$(CC)' '$(HOSTCC)' $(incpath) $(sysdef) > $@ + +clean:: + $(call QUIET_CLEAN, loongarch) $(RM) $(header) + +archheaders: $(header) diff --git a/tools/perf/arch/loongarch/annotate/instructions.c b/tools/perf/arch/loongarch/annotate/instructions.c new file mode 100644 index 000000000000..ab21bf122135 --- /dev/null +++ b/tools/perf/arch/loongarch/annotate/instructions.c @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Perf annotate functions. + * + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited + */ + +static +struct ins_ops *loongarch__associate_ins_ops(struct arch *arch, const char *name) +{ + struct ins_ops *ops = NULL; + + if (!strncmp(name, "beqz", 4) || + !strncmp(name, "bnez", 4) || + !strncmp(name, "beq", 3) || + !strncmp(name, "bne", 3) || + !strncmp(name, "blt", 3) || + !strncmp(name, "bge", 3) || + !strncmp(name, "bltu", 4) || + !strncmp(name, "bgeu", 4) || + !strncmp(name, "bl", 2)) + ops = &call_ops; + else if (!strncmp(name, "jirl", 4)) + ops = &ret_ops; + else if (name[0] == 'b') + ops = &jump_ops; + else + return NULL; + + arch__associate_ins_ops(arch, name, ops); + + return ops; +} + +static +int loongarch__annotate_init(struct arch *arch, char *cpuid __maybe_unused) +{ + if (!arch->initialized) { + arch->associate_instruction_ops = loongarch__associate_ins_ops; + arch->initialized = true; + arch->objdump.comment_char = '#'; + } + + return 0; +} diff --git a/tools/perf/arch/loongarch/entry/syscalls/mksyscalltbl b/tools/perf/arch/loongarch/entry/syscalls/mksyscalltbl new file mode 100755 index 000000000000..c52156f7204d --- /dev/null +++ b/tools/perf/arch/loongarch/entry/syscalls/mksyscalltbl @@ -0,0 +1,61 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# Generate system call table for perf. Derived from +# powerpc script. +# +# Author(s): Ming Wang <wangming01@loongson.cn> +# Author(s): Huacai Chen <chenhuacai@loongson.cn> +# Copyright (C) 2020-2023 Loongson Technology Corporation Limited + +gcc=$1 +hostcc=$2 +incpath=$3 +input=$4 + +if ! test -r $input; then + echo "Could not read input file" >&2 + exit 1 +fi + +create_table_from_c() +{ + local sc nr last_sc + + create_table_exe=`mktemp ${TMPDIR:-/tmp}/create-table-XXXXXX` + + { + + cat <<-_EoHEADER + #include <stdio.h> + #include "$input" + int main(int argc, char *argv[]) + { + _EoHEADER + + while read sc nr; do + printf "%s\n" " printf(\"\\t[%d] = \\\"$sc\\\",\\n\", $nr);" + last_sc=$nr + done + + printf "%s\n" " printf(\"#define SYSCALLTBL_LOONGARCH_MAX_ID %d\\n\", $last_sc);" + printf "}\n" + + } | $hostcc -I $incpath/include/uapi -o $create_table_exe -x c - + + $create_table_exe + + rm -f $create_table_exe +} + +create_table() +{ + echo "static const char *syscalltbl_loongarch[] = {" + create_table_from_c + echo "};" +} + +$gcc -E -dM -x c -I $incpath/include/uapi $input \ + |sed -ne 's/^#define __NR_//p' \ + |sort -t' ' -k2 -n \ + |create_table diff --git a/tools/perf/arch/loongarch/include/dwarf-regs-table.h b/tools/perf/arch/loongarch/include/dwarf-regs-table.h new file mode 100644 index 000000000000..bb3944f5764a --- /dev/null +++ b/tools/perf/arch/loongarch/include/dwarf-regs-table.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * dwarf-regs-table.h : Mapping of DWARF debug register numbers into + * register names. + * + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited + */ + +#ifdef DEFINE_DWARF_REGSTR_TABLE +static const char * const loongarch_regstr_tbl[] = { + "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7", + "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", + "%r16", "%r17", "%r18", "%r19", "%r20", "%r21", "%r22", "%r23", + "%r24", "%r25", "%r26", "%r27", "%r28", "%r29", "%r30", "%r31", +}; +#endif diff --git a/tools/perf/arch/loongarch/include/perf_regs.h b/tools/perf/arch/loongarch/include/perf_regs.h new file mode 100644 index 000000000000..7833c7dbd38d --- /dev/null +++ b/tools/perf/arch/loongarch/include/perf_regs.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef ARCH_PERF_REGS_H +#define ARCH_PERF_REGS_H + +#include <stdlib.h> +#include <linux/types.h> +#include <asm/perf_regs.h> + +#define PERF_REGS_MAX PERF_REG_LOONGARCH_MAX +#define PERF_REG_IP PERF_REG_LOONGARCH_PC +#define PERF_REG_SP PERF_REG_LOONGARCH_R3 + +#define PERF_REGS_MASK ((1ULL << PERF_REG_LOONGARCH_MAX) - 1) + +#endif /* ARCH_PERF_REGS_H */ diff --git a/tools/perf/arch/loongarch/util/Build b/tools/perf/arch/loongarch/util/Build new file mode 100644 index 000000000000..d776125a2d06 --- /dev/null +++ b/tools/perf/arch/loongarch/util/Build @@ -0,0 +1,5 @@ +perf-y += perf_regs.o + +perf-$(CONFIG_DWARF) += dwarf-regs.o +perf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o +perf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o diff --git a/tools/perf/arch/loongarch/util/dwarf-regs.c b/tools/perf/arch/loongarch/util/dwarf-regs.c new file mode 100644 index 000000000000..0f6ebc387463 --- /dev/null +++ b/tools/perf/arch/loongarch/util/dwarf-regs.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * dwarf-regs.c : Mapping of DWARF debug register numbers into register names. + * + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited + */ + +#include <stdio.h> +#include <errno.h> /* for EINVAL */ +#include <string.h> /* for strcmp */ +#include <dwarf-regs.h> + +struct pt_regs_dwarfnum { + const char *name; + unsigned int dwarfnum; +}; + +static struct pt_regs_dwarfnum loongarch_gpr_table[] = { + {"%r0", 0}, {"%r1", 1}, {"%r2", 2}, {"%r3", 3}, + {"%r4", 4}, {"%r5", 5}, {"%r6", 6}, {"%r7", 7}, + {"%r8", 8}, {"%r9", 9}, {"%r10", 10}, {"%r11", 11}, + {"%r12", 12}, {"%r13", 13}, {"%r14", 14}, {"%r15", 15}, + {"%r16", 16}, {"%r17", 17}, {"%r18", 18}, {"%r19", 19}, + {"%r20", 20}, {"%r21", 21}, {"%r22", 22}, {"%r23", 23}, + {"%r24", 24}, {"%r25", 25}, {"%r26", 26}, {"%r27", 27}, + {"%r28", 28}, {"%r29", 29}, {"%r30", 30}, {"%r31", 31}, + {NULL, 0} +}; + +const char *get_arch_regstr(unsigned int n) +{ + n %= 32; + return loongarch_gpr_table[n].name; +} + +int regs_query_register_offset(const char *name) +{ + const struct pt_regs_dwarfnum *roff; + + for (roff = loongarch_gpr_table; roff->name != NULL; roff++) + if (!strcmp(roff->name, name)) + return roff->dwarfnum; + return -EINVAL; +} diff --git a/tools/perf/arch/loongarch/util/perf_regs.c b/tools/perf/arch/loongarch/util/perf_regs.c new file mode 100644 index 000000000000..2833e101a7c6 --- /dev/null +++ b/tools/perf/arch/loongarch/util/perf_regs.c @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "../../../util/perf_regs.h" + +const struct sample_reg sample_reg_masks[] = { + SMPL_REG_END +}; diff --git a/tools/perf/arch/loongarch/util/unwind-libdw.c b/tools/perf/arch/loongarch/util/unwind-libdw.c new file mode 100644 index 000000000000..a9415385230a --- /dev/null +++ b/tools/perf/arch/loongarch/util/unwind-libdw.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2020-2023 Loongson Technology Corporation Limited */ + +#include <elfutils/libdwfl.h> +#include "../../util/unwind-libdw.h" +#include "../../util/perf_regs.h" +#include "../../util/sample.h" + +bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg) +{ + struct unwind_info *ui = arg; + struct regs_dump *user_regs = &ui->sample->user_regs; + Dwarf_Word dwarf_regs[PERF_REG_LOONGARCH_MAX]; + +#define REG(r) ({ \ + Dwarf_Word val = 0; \ + perf_reg_value(&val, user_regs, PERF_REG_LOONGARCH_##r); \ + val; \ +}) + + dwarf_regs[0] = 0; + dwarf_regs[1] = REG(R1); + dwarf_regs[2] = REG(R2); + dwarf_regs[3] = REG(R3); + dwarf_regs[4] = REG(R4); + dwarf_regs[5] = REG(R5); + dwarf_regs[6] = REG(R6); + dwarf_regs[7] = REG(R7); + dwarf_regs[8] = REG(R8); + dwarf_regs[9] = REG(R9); + dwarf_regs[10] = REG(R10); + dwarf_regs[11] = REG(R11); + dwarf_regs[12] = REG(R12); + dwarf_regs[13] = REG(R13); + dwarf_regs[14] = REG(R14); + dwarf_regs[15] = REG(R15); + dwarf_regs[16] = REG(R16); + dwarf_regs[17] = REG(R17); + dwarf_regs[18] = REG(R18); + dwarf_regs[19] = REG(R19); + dwarf_regs[20] = REG(R20); + dwarf_regs[21] = REG(R21); + dwarf_regs[22] = REG(R22); + dwarf_regs[23] = REG(R23); + dwarf_regs[24] = REG(R24); + dwarf_regs[25] = REG(R25); + dwarf_regs[26] = REG(R26); + dwarf_regs[27] = REG(R27); + dwarf_regs[28] = REG(R28); + dwarf_regs[29] = REG(R29); + dwarf_regs[30] = REG(R30); + dwarf_regs[31] = REG(R31); + dwfl_thread_state_register_pc(thread, REG(PC)); + + return dwfl_thread_state_registers(thread, 0, PERF_REG_LOONGARCH_MAX, dwarf_regs); +} diff --git a/tools/perf/arch/loongarch/util/unwind-libunwind.c b/tools/perf/arch/loongarch/util/unwind-libunwind.c new file mode 100644 index 000000000000..f693167b86ef --- /dev/null +++ b/tools/perf/arch/loongarch/util/unwind-libunwind.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <errno.h> +#include <libunwind.h> +#include "perf_regs.h" +#include "../../util/unwind.h" +#include "util/debug.h" + +int libunwind__arch_reg_id(int regnum) +{ + switch (regnum) { + case UNW_LOONGARCH64_R1: + return PERF_REG_LOONGARCH_R1; + case UNW_LOONGARCH64_R2: + return PERF_REG_LOONGARCH_R2; + case UNW_LOONGARCH64_R3: + return PERF_REG_LOONGARCH_R3; + case UNW_LOONGARCH64_R4: + return PERF_REG_LOONGARCH_R4; + case UNW_LOONGARCH64_R5: + return PERF_REG_LOONGARCH_R5; + case UNW_LOONGARCH64_R6: + return PERF_REG_LOONGARCH_R6; + case UNW_LOONGARCH64_R7: + return PERF_REG_LOONGARCH_R7; + case UNW_LOONGARCH64_R8: + return PERF_REG_LOONGARCH_R8; + case UNW_LOONGARCH64_R9: + return PERF_REG_LOONGARCH_R9; + case UNW_LOONGARCH64_R10: + return PERF_REG_LOONGARCH_R10; + case UNW_LOONGARCH64_R11: + return PERF_REG_LOONGARCH_R11; + case UNW_LOONGARCH64_R12: + return PERF_REG_LOONGARCH_R12; + case UNW_LOONGARCH64_R13: + return PERF_REG_LOONGARCH_R13; + case UNW_LOONGARCH64_R14: + return PERF_REG_LOONGARCH_R14; + case UNW_LOONGARCH64_R15: + return PERF_REG_LOONGARCH_R15; + case UNW_LOONGARCH64_R16: + return PERF_REG_LOONGARCH_R16; + case UNW_LOONGARCH64_R17: + return PERF_REG_LOONGARCH_R17; + case UNW_LOONGARCH64_R18: + return PERF_REG_LOONGARCH_R18; + case UNW_LOONGARCH64_R19: + return PERF_REG_LOONGARCH_R19; + case UNW_LOONGARCH64_R20: + return PERF_REG_LOONGARCH_R20; + case UNW_LOONGARCH64_R21: + return PERF_REG_LOONGARCH_R21; + case UNW_LOONGARCH64_R22: + return PERF_REG_LOONGARCH_R22; + case UNW_LOONGARCH64_R23: + return PERF_REG_LOONGARCH_R23; + case UNW_LOONGARCH64_R24: + return PERF_REG_LOONGARCH_R24; + case UNW_LOONGARCH64_R25: + return PERF_REG_LOONGARCH_R25; + case UNW_LOONGARCH64_R26: + return PERF_REG_LOONGARCH_R26; + case UNW_LOONGARCH64_R27: + return PERF_REG_LOONGARCH_R27; + case UNW_LOONGARCH64_R28: + return PERF_REG_LOONGARCH_R28; + case UNW_LOONGARCH64_R29: + return PERF_REG_LOONGARCH_R29; + case UNW_LOONGARCH64_R30: + return PERF_REG_LOONGARCH_R30; + case UNW_LOONGARCH64_R31: + return PERF_REG_LOONGARCH_R31; + case UNW_LOONGARCH64_PC: + return PERF_REG_LOONGARCH_PC; + default: + pr_err("unwind: invalid reg id %d\n", regnum); + return -EINVAL; + } + + return -EINVAL; +} diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index f8182417b734..10bb1d494258 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -538,6 +538,7 @@ static int perf_event__repipe_buildid_mmap2(struct perf_tool *tool, dso->hit = 1; } dso__put(dso); + perf_event__repipe(tool, event, sample, machine); return 0; } diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 5d18a5a6f662..fa7c40956d0f 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -539,12 +539,7 @@ static int enable_counters(void) return err; } - /* - * We need to enable counters only if: - * - we don't have tracee (attaching to task or cpu) - * - we have initial delay configured - */ - if (!target__none(&target)) { + if (!target__enable_on_exec(&target)) { if (!all_counters_use_bpf) evlist__enable(evsel_list); } @@ -914,7 +909,7 @@ try_again_reset: return err; } - if (stat_config.initial_delay) { + if (target.initial_delay) { pr_info(EVLIST_DISABLED_MSG); } else { err = enable_counters(); @@ -926,8 +921,8 @@ try_again_reset: if (forks) evlist__start_workload(evsel_list); - if (stat_config.initial_delay > 0) { - usleep(stat_config.initial_delay * USEC_PER_MSEC); + if (target.initial_delay > 0) { + usleep(target.initial_delay * USEC_PER_MSEC); err = enable_counters(); if (err) return -1; @@ -1248,7 +1243,7 @@ static struct option stat_options[] = { "aggregate counts per thread", AGGR_THREAD), OPT_SET_UINT(0, "per-node", &stat_config.aggr_mode, "aggregate counts per numa node", AGGR_NODE), - OPT_INTEGER('D', "delay", &stat_config.initial_delay, + OPT_INTEGER('D', "delay", &target.initial_delay, "ms to wait before starting measurement after program start (-1: start with events disabled)"), OPT_CALLBACK_NOOPT(0, "metric-only", &stat_config.metric_only, NULL, "Only print computed metrics. No raw values", enable_metric_only), diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index eacca9a874e2..9d6232f681ce 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh @@ -40,6 +40,7 @@ arch/x86/lib/x86-opcode-map.txt arch/x86/tools/gen-insn-attr-x86.awk arch/arm/include/uapi/asm/perf_regs.h arch/arm64/include/uapi/asm/perf_regs.h +arch/loongarch/include/uapi/asm/perf_regs.h arch/mips/include/uapi/asm/perf_regs.h arch/powerpc/include/uapi/asm/perf_regs.h arch/s390/include/uapi/asm/perf_regs.h diff --git a/tools/perf/tests/shell/lib/perf_json_output_lint.py b/tools/perf/tests/shell/lib/perf_json_output_lint.py index d90f8d102eb9..97598d14e532 100644 --- a/tools/perf/tests/shell/lib/perf_json_output_lint.py +++ b/tools/perf/tests/shell/lib/perf_json_output_lint.py @@ -40,19 +40,6 @@ def is_counter_value(num): return isfloat(num) or num == '<not counted>' or num == '<not supported>' def check_json_output(expected_items): - if expected_items != -1: - for line in Lines: - if 'failed' not in line: - count = 0 - count = line.count(',') - if count != expected_items and count >= 1 and count <= 3 and 'metric-value' in line: - # Events that generate >1 metric may have isolated metric - # values and possibly other prefixes like interval, core and - # aggregate-number. - continue - if count != expected_items: - raise RuntimeError(f'wrong number of fields. counted {count} expected {expected_items}' - f' in \'{line}\'') checks = { 'aggregate-number': lambda x: isfloat(x), 'core': lambda x: True, @@ -73,6 +60,16 @@ def check_json_output(expected_items): } input = '[\n' + ','.join(Lines) + '\n]' for item in json.loads(input): + if expected_items != -1: + count = len(item) + if count != expected_items and count >= 1 and count <= 4 and 'metric-value' in item: + # Events that generate >1 metric may have isolated metric + # values and possibly other prefixes like interval, core and + # aggregate-number. + pass + elif count != expected_items: + raise RuntimeError(f'wrong number of fields. counted {count} expected {expected_items}' + f' in \'{item}\'') for key, value in item.items(): if key not in checks: raise RuntimeError(f'Unexpected key: key={key} value={value}') @@ -82,11 +79,11 @@ def check_json_output(expected_items): try: if args.no_args or args.system_wide or args.event: - expected_items = 6 - elif args.interval or args.per_thread or args.system_wide_no_aggr: expected_items = 7 - elif args.per_core or args.per_socket or args.per_node or args.per_die: + elif args.interval or args.per_thread or args.system_wide_no_aggr: expected_items = 8 + elif args.per_core or args.per_socket or args.per_node or args.per_die: + expected_items = 9 else: # If no option is specified, don't check the number of items. expected_items = -1 diff --git a/tools/perf/tests/shell/stat+csv_output.sh b/tools/perf/tests/shell/stat+csv_output.sh index b7f050aa6210..324fc9e6edd7 100755 --- a/tools/perf/tests/shell/stat+csv_output.sh +++ b/tools/perf/tests/shell/stat+csv_output.sh @@ -7,6 +7,7 @@ set -e skip_test=0 +csv_sep=@ function commachecker() { @@ -34,7 +35,7 @@ function commachecker() [ "$x" = "Failed" ] && continue # Count the number of commas - x=$(echo $line | tr -d -c ',') + x=$(echo $line | tr -d -c $csv_sep) cnt="${#x}" # echo $line $cnt [[ ! "$cnt" =~ $exp ]] && { @@ -54,7 +55,7 @@ function ParanoidAndNotRoot() check_no_args() { echo -n "Checking CSV output: no args " - perf stat -x, true 2>&1 | commachecker --no-args + perf stat -x$csv_sep true 2>&1 | commachecker --no-args echo "[Success]" } @@ -66,7 +67,7 @@ check_system_wide() echo "[Skip] paranoid and not root" return fi - perf stat -x, -a true 2>&1 | commachecker --system-wide + perf stat -x$csv_sep -a true 2>&1 | commachecker --system-wide echo "[Success]" } @@ -79,14 +80,14 @@ check_system_wide_no_aggr() return fi echo -n "Checking CSV output: system wide no aggregation " - perf stat -x, -A -a --no-merge true 2>&1 | commachecker --system-wide-no-aggr + perf stat -x$csv_sep -A -a --no-merge true 2>&1 | commachecker --system-wide-no-aggr echo "[Success]" } check_interval() { echo -n "Checking CSV output: interval " - perf stat -x, -I 1000 true 2>&1 | commachecker --interval + perf stat -x$csv_sep -I 1000 true 2>&1 | commachecker --interval echo "[Success]" } @@ -94,7 +95,7 @@ check_interval() check_event() { echo -n "Checking CSV output: event " - perf stat -x, -e cpu-clock true 2>&1 | commachecker --event + perf stat -x$csv_sep -e cpu-clock true 2>&1 | commachecker --event echo "[Success]" } @@ -106,7 +107,7 @@ check_per_core() echo "[Skip] paranoid and not root" return fi - perf stat -x, --per-core -a true 2>&1 | commachecker --per-core + perf stat -x$csv_sep --per-core -a true 2>&1 | commachecker --per-core echo "[Success]" } @@ -118,7 +119,7 @@ check_per_thread() echo "[Skip] paranoid and not root" return fi - perf stat -x, --per-thread -a true 2>&1 | commachecker --per-thread + perf stat -x$csv_sep --per-thread -a true 2>&1 | commachecker --per-thread echo "[Success]" } @@ -130,7 +131,7 @@ check_per_die() echo "[Skip] paranoid and not root" return fi - perf stat -x, --per-die -a true 2>&1 | commachecker --per-die + perf stat -x$csv_sep --per-die -a true 2>&1 | commachecker --per-die echo "[Success]" } @@ -142,7 +143,7 @@ check_per_node() echo "[Skip] paranoid and not root" return fi - perf stat -x, --per-node -a true 2>&1 | commachecker --per-node + perf stat -x$csv_sep --per-node -a true 2>&1 | commachecker --per-node echo "[Success]" } @@ -154,7 +155,7 @@ check_per_socket() echo "[Skip] paranoid and not root" return fi - perf stat -x, --per-socket -a true 2>&1 | commachecker --per-socket + perf stat -x$csv_sep --per-socket -a true 2>&1 | commachecker --per-socket echo "[Success]" } diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index db475e44f42f..0cc7710f32da 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -149,6 +149,7 @@ static int arch__associate_ins_ops(struct arch* arch, const char *name, struct i #include "arch/arm/annotate/instructions.c" #include "arch/arm64/annotate/instructions.c" #include "arch/csky/annotate/instructions.c" +#include "arch/loongarch/annotate/instructions.c" #include "arch/mips/annotate/instructions.c" #include "arch/x86/annotate/instructions.c" #include "arch/powerpc/annotate/instructions.c" @@ -211,6 +212,13 @@ static struct arch architectures[] = { .comment_char = '#', }, }, + { + .name = "loongarch", + .init = loongarch__annotate_init, + .objdump = { + .comment_char = '#', + }, + }, }; static void ins__delete(struct ins_operands *ops) diff --git a/tools/perf/util/bpf_skel/off_cpu.bpf.c b/tools/perf/util/bpf_skel/off_cpu.bpf.c index 38e3b287dbb2..d877a0a9731f 100644 --- a/tools/perf/util/bpf_skel/off_cpu.bpf.c +++ b/tools/perf/util/bpf_skel/off_cpu.bpf.c @@ -277,7 +277,7 @@ int on_switch(u64 *ctx) else prev_state = get_task_state(prev); - return off_cpu_stat(ctx, prev, next, prev_state); + return off_cpu_stat(ctx, prev, next, prev_state & 0xff); } char LICENSE[] SEC("license") = "Dual BSD/GPL"; diff --git a/tools/perf/util/dwarf-regs.c b/tools/perf/util/dwarf-regs.c index 3fa4486742cd..69cfaa5953bf 100644 --- a/tools/perf/util/dwarf-regs.c +++ b/tools/perf/util/dwarf-regs.c @@ -14,6 +14,10 @@ #define EM_AARCH64 183 /* ARM 64 bit */ #endif +#ifndef EM_LOONGARCH +#define EM_LOONGARCH 258 /* LoongArch */ +#endif + /* Define const char * {arch}_register_tbl[] */ #define DEFINE_DWARF_REGSTR_TABLE #include "../arch/x86/include/dwarf-regs-table.h" @@ -25,6 +29,7 @@ #include "../arch/sparc/include/dwarf-regs-table.h" #include "../arch/xtensa/include/dwarf-regs-table.h" #include "../arch/mips/include/dwarf-regs-table.h" +#include "../arch/loongarch/include/dwarf-regs-table.h" #define __get_dwarf_regstr(tbl, n) (((n) < ARRAY_SIZE(tbl)) ? (tbl)[(n)] : NULL) @@ -56,6 +61,8 @@ const char *get_dwarf_regstr(unsigned int n, unsigned int machine) return __get_dwarf_regstr(xtensa_regstr_tbl, n); case EM_MIPS: return __get_dwarf_regstr(mips_regstr_tbl, n); + case EM_LOONGARCH: + return __get_dwarf_regstr(loongarch_regstr_tbl, n); default: pr_err("ELF MACHINE %x is not supported.\n", machine); } diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c index 5b8cf6a421a4..0d5d40cb997b 100644 --- a/tools/perf/util/env.c +++ b/tools/perf/util/env.c @@ -435,6 +435,8 @@ static const char *normalize_arch(char *arch) return "mips"; if (!strncmp(arch, "sh", 2) && isdigit(arch[2])) return "sh"; + if (!strncmp(arch, "loongarch", 9)) + return "loongarch"; return arch; } diff --git a/tools/perf/util/genelf.h b/tools/perf/util/genelf.h index 6af062d1c452..5f18d20ea903 100644 --- a/tools/perf/util/genelf.h +++ b/tools/perf/util/genelf.h @@ -43,6 +43,9 @@ int jit_add_debug_info(Elf *e, uint64_t code_addr, void *debug, int nr_debug_ent #elif defined(__riscv) && __riscv_xlen == 64 #define GEN_ELF_ARCH EM_RISCV #define GEN_ELF_CLASS ELFCLASS64 +#elif defined(__loongarch__) +#define GEN_ELF_ARCH EM_LOONGARCH +#define GEN_ELF_CLASS ELFCLASS64 #else #error "unsupported architecture" #endif diff --git a/tools/perf/util/perf_regs.c b/tools/perf/util/perf_regs.c index 57a567ee2cea..9bdbaa37f813 100644 --- a/tools/perf/util/perf_regs.c +++ b/tools/perf/util/perf_regs.c @@ -28,6 +28,7 @@ uint64_t __weak arch__user_reg_mask(void) #include "../../arch/arm/include/uapi/asm/perf_regs.h" #include "../../arch/csky/include/uapi/asm/perf_regs.h" +#include "../../arch/loongarch/include/uapi/asm/perf_regs.h" #include "../../arch/mips/include/uapi/asm/perf_regs.h" #include "../../arch/powerpc/include/uapi/asm/perf_regs.h" #include "../../arch/riscv/include/uapi/asm/perf_regs.h" @@ -236,6 +237,79 @@ static const char *__perf_reg_name_csky(int id) return NULL; } +static inline const char *__perf_reg_name_loongarch(int id) +{ + switch (id) { + case PERF_REG_LOONGARCH_PC: + return "PC"; + case PERF_REG_LOONGARCH_R1: + return "%r1"; + case PERF_REG_LOONGARCH_R2: + return "%r2"; + case PERF_REG_LOONGARCH_R3: + return "%r3"; + case PERF_REG_LOONGARCH_R4: + return "%r4"; + case PERF_REG_LOONGARCH_R5: + return "%r5"; + case PERF_REG_LOONGARCH_R6: + return "%r6"; + case PERF_REG_LOONGARCH_R7: + return "%r7"; + case PERF_REG_LOONGARCH_R8: + return "%r8"; + case PERF_REG_LOONGARCH_R9: + return "%r9"; + case PERF_REG_LOONGARCH_R10: + return "%r10"; + case PERF_REG_LOONGARCH_R11: + return "%r11"; + case PERF_REG_LOONGARCH_R12: + return "%r12"; + case PERF_REG_LOONGARCH_R13: + return "%r13"; + case PERF_REG_LOONGARCH_R14: + return "%r14"; + case PERF_REG_LOONGARCH_R15: + return "%r15"; + case PERF_REG_LOONGARCH_R16: + return "%r16"; + case PERF_REG_LOONGARCH_R17: + return "%r17"; + case PERF_REG_LOONGARCH_R18: + return "%r18"; + case PERF_REG_LOONGARCH_R19: + return "%r19"; + case PERF_REG_LOONGARCH_R20: + return "%r20"; + case PERF_REG_LOONGARCH_R21: + return "%r21"; + case PERF_REG_LOONGARCH_R22: + return "%r22"; + case PERF_REG_LOONGARCH_R23: + return "%r23"; + case PERF_REG_LOONGARCH_R24: + return "%r24"; + case PERF_REG_LOONGARCH_R25: + return "%r25"; + case PERF_REG_LOONGARCH_R26: + return "%r26"; + case PERF_REG_LOONGARCH_R27: + return "%r27"; + case PERF_REG_LOONGARCH_R28: + return "%r28"; + case PERF_REG_LOONGARCH_R29: + return "%r29"; + case PERF_REG_LOONGARCH_R30: + return "%r30"; + case PERF_REG_LOONGARCH_R31: + return "%r31"; + default: + break; + } + return NULL; +} + static const char *__perf_reg_name_mips(int id) { switch (id) { @@ -670,6 +744,8 @@ const char *perf_reg_name(int id, const char *arch) if (!strcmp(arch, "csky")) reg_name = __perf_reg_name_csky(id); + else if (!strcmp(arch, "loongarch")) + reg_name = __perf_reg_name_loongarch(id); else if (!strcmp(arch, "mips")) reg_name = __perf_reg_name_mips(id); else if (!strcmp(arch, "powerpc")) diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index 534d36d26fc3..a07473703c6d 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -842,11 +842,7 @@ int create_perf_stat_counter(struct evsel *evsel, if (evsel__is_group_leader(evsel)) { attr->disabled = 1; - /* - * In case of initial_delay we enable tracee - * events manually. - */ - if (target__none(target) && !config->initial_delay) + if (target__enable_on_exec(target)) attr->enable_on_exec = 1; } diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index b1c29156c560..bf1794ebc916 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h @@ -166,7 +166,6 @@ struct perf_stat_config { FILE *output; unsigned int interval; unsigned int timeout; - int initial_delay; unsigned int unit_width; unsigned int metric_only_len; int times; diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 41882ae8452e..554289fd6df9 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -213,7 +213,7 @@ Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, Elf_Scn *sec = NULL; size_t cnt = 1; - /* Elf is corrupted/truncated, avoid calling elf_strptr. */ + /* ELF is corrupted/truncated, avoid calling elf_strptr. */ if (!elf_rawdata(elf_getscn(elf, ep->e_shstrndx), NULL)) return NULL; diff --git a/tools/perf/util/syscalltbl.c b/tools/perf/util/syscalltbl.c index a2e906858891..313eccef6cb4 100644 --- a/tools/perf/util/syscalltbl.c +++ b/tools/perf/util/syscalltbl.c @@ -38,6 +38,10 @@ static const char **syscalltbl_native = syscalltbl_arm64; #include <asm/syscalls_n64.c> const int syscalltbl_native_max_id = SYSCALLTBL_MIPS_N64_MAX_ID; static const char **syscalltbl_native = syscalltbl_mips_n64; +#elif defined(__loongarch__) +#include <asm/syscalls.c> +const int syscalltbl_native_max_id = SYSCALLTBL_LOONGARCH_MAX_ID; +static const char **syscalltbl_native = syscalltbl_loongarch; #endif struct syscall { diff --git a/tools/perf/util/target.h b/tools/perf/util/target.h index daec6cba500d..880f1af7f6ad 100644 --- a/tools/perf/util/target.h +++ b/tools/perf/util/target.h @@ -18,6 +18,7 @@ struct target { bool per_thread; bool use_bpf; bool hybrid; + int initial_delay; const char *attr_map; }; @@ -72,6 +73,17 @@ static inline bool target__none(struct target *target) return !target__has_task(target) && !target__has_cpu(target); } +static inline bool target__enable_on_exec(struct target *target) +{ + /* + * Normally enable_on_exec should be set if: + * 1) The tracee process is forked (not attaching to existed task or cpu). + * 2) And initial_delay is not configured. + * Otherwise, we enable tracee events manually. + */ + return target__none(target) && !target->initial_delay; +} + static inline bool target__has_per_thread(struct target *target) { return target->system_wide && target->per_thread; |