diff options
Diffstat (limited to 'tools')
125 files changed, 2591 insertions, 729 deletions
diff --git a/tools/arch/alpha/include/uapi/asm/mman.h b/tools/arch/alpha/include/uapi/asm/mman.h new file mode 100644 index 000000000000..e38b64c82b97 --- /dev/null +++ b/tools/arch/alpha/include/uapi/asm/mman.h @@ -0,0 +1,47 @@ +#ifndef TOOLS_ARCH_ALPHA_UAPI_ASM_MMAN_FIX_H +#define TOOLS_ARCH_ALPHA_UAPI_ASM_MMAN_FIX_H +#define MADV_DODUMP 17 +#define MADV_DOFORK 11 +#define MADV_DONTDUMP 16 +#define MADV_DONTFORK 10 +#define MADV_DONTNEED 6 +#define MADV_FREE 8 +#define MADV_HUGEPAGE 14 +#define MADV_MERGEABLE 12 +#define MADV_NOHUGEPAGE 15 +#define MADV_NORMAL 0 +#define MADV_RANDOM 1 +#define MADV_REMOVE 9 +#define MADV_SEQUENTIAL 2 +#define MADV_UNMERGEABLE 13 +#define MADV_WILLNEED 3 +#define MAP_ANONYMOUS 0x10 +#define MAP_DENYWRITE 0x02000 +#define MAP_EXECUTABLE 0x04000 +#define MAP_FILE 0 +#define MAP_FIXED 0x100 +#define MAP_GROWSDOWN 0x01000 +#define MAP_HUGETLB 0x100000 +#define MAP_LOCKED 0x08000 +#define MAP_NONBLOCK 0x40000 +#define MAP_NORESERVE 0x10000 +#define MAP_POPULATE 0x20000 +#define MAP_PRIVATE 0x02 +#define MAP_SHARED 0x01 +#define MAP_STACK 0x80000 +#define PROT_EXEC 0x4 +#define PROT_GROWSDOWN 0x01000000 +#define PROT_GROWSUP 0x02000000 +#define PROT_NONE 0x0 +#define PROT_READ 0x1 +#define PROT_SEM 0x8 +#define PROT_WRITE 0x2 +/* MADV_HWPOISON is undefined on alpha, fix it for perf */ +#define MADV_HWPOISON 100 +/* MADV_SOFT_OFFLINE is undefined on alpha, fix it for perf */ +#define MADV_SOFT_OFFLINE 101 +/* MAP_32BIT is undefined on alpha, fix it for perf */ +#define MAP_32BIT 0 +/* MAP_UNINITIALIZED is undefined on alpha, fix it for perf */ +#define MAP_UNINITIALIZED 0 +#endif diff --git a/tools/arch/arc/include/uapi/asm/mman.h b/tools/arch/arc/include/uapi/asm/mman.h new file mode 100644 index 000000000000..aa3acd2aa9af --- /dev/null +++ b/tools/arch/arc/include/uapi/asm/mman.h @@ -0,0 +1,6 @@ +#ifndef TOOLS_ARCH_ARC_UAPI_ASM_MMAN_FIX_H +#define TOOLS_ARCH_ARC_UAPI_ASM_MMAN_FIX_H +#include <uapi/asm-generic/mman.h> +/* MAP_32BIT is undefined on arc, fix it for perf */ +#define MAP_32BIT 0 +#endif diff --git a/tools/arch/arm/include/uapi/asm/mman.h b/tools/arch/arm/include/uapi/asm/mman.h new file mode 100644 index 000000000000..478f699f56fd --- /dev/null +++ b/tools/arch/arm/include/uapi/asm/mman.h @@ -0,0 +1,6 @@ +#ifndef TOOLS_ARCH_ARM_UAPI_ASM_MMAN_FIX_H +#define TOOLS_ARCH_ARM_UAPI_ASM_MMAN_FIX_H +#include <uapi/asm-generic/mman.h> +/* MAP_32BIT is undefined on arm, fix it for perf */ +#define MAP_32BIT 0 +#endif diff --git a/tools/arch/arm64/include/uapi/asm/mman.h b/tools/arch/arm64/include/uapi/asm/mman.h new file mode 100644 index 000000000000..70fd3113710a --- /dev/null +++ b/tools/arch/arm64/include/uapi/asm/mman.h @@ -0,0 +1,6 @@ +#ifndef TOOLS_ARCH_ARM64_UAPI_ASM_MMAN_FIX_H +#define TOOLS_ARCH_ARM64_UAPI_ASM_MMAN_FIX_H +#include <uapi/asm-generic/mman.h> +/* MAP_32BIT is undefined on arm64, fix it for perf */ +#define MAP_32BIT 0 +#endif diff --git a/tools/arch/frv/include/uapi/asm/mman.h b/tools/arch/frv/include/uapi/asm/mman.h new file mode 100644 index 000000000000..5be78ac12464 --- /dev/null +++ b/tools/arch/frv/include/uapi/asm/mman.h @@ -0,0 +1,6 @@ +#ifndef TOOLS_ARCH_FRV_UAPI_ASM_MMAN_FIX_H +#define TOOLS_ARCH_FRV_UAPI_ASM_MMAN_FIX_H +#include <uapi/asm-generic/mman.h> +/* MAP_32BIT is undefined on frv, fix it for perf */ +#define MAP_32BIT 0 +#endif diff --git a/tools/arch/h8300/include/uapi/asm/mman.h b/tools/arch/h8300/include/uapi/asm/mman.h new file mode 100644 index 000000000000..9d9ac54d3c5a --- /dev/null +++ b/tools/arch/h8300/include/uapi/asm/mman.h @@ -0,0 +1,6 @@ +#ifndef TOOLS_ARCH_H8300_UAPI_ASM_MMAN_FIX_H +#define TOOLS_ARCH_H8300_UAPI_ASM_MMAN_FIX_H +#include <uapi/asm-generic/mman.h> +/* MAP_32BIT is undefined on h8300, fix it for perf */ +#define MAP_32BIT 0 +#endif diff --git a/tools/arch/hexagon/include/uapi/asm/mman.h b/tools/arch/hexagon/include/uapi/asm/mman.h new file mode 100644 index 000000000000..102f3fae6085 --- /dev/null +++ b/tools/arch/hexagon/include/uapi/asm/mman.h @@ -0,0 +1,6 @@ +#ifndef TOOLS_ARCH_HEXAGON_UAPI_ASM_MMAN_FIX_H +#define TOOLS_ARCH_HEXAGON_UAPI_ASM_MMAN_FIX_H +#include <uapi/asm-generic/mman.h> +/* MAP_32BIT is undefined on hexagon, fix it for perf */ +#define MAP_32BIT 0 +#endif diff --git a/tools/arch/ia64/include/uapi/asm/mman.h b/tools/arch/ia64/include/uapi/asm/mman.h new file mode 100644 index 000000000000..1d6e5ac6442d --- /dev/null +++ b/tools/arch/ia64/include/uapi/asm/mman.h @@ -0,0 +1,6 @@ +#ifndef TOOLS_ARCH_IA64_UAPI_ASM_MMAN_FIX_H +#define TOOLS_ARCH_IA64_UAPI_ASM_MMAN_FIX_H +#include <uapi/asm-generic/mman.h> +/* MAP_32BIT is undefined on ia64, fix it for perf */ +#define MAP_32BIT 0 +#endif diff --git a/tools/arch/m32r/include/uapi/asm/mman.h b/tools/arch/m32r/include/uapi/asm/mman.h new file mode 100644 index 000000000000..1c29635bb73b --- /dev/null +++ b/tools/arch/m32r/include/uapi/asm/mman.h @@ -0,0 +1,6 @@ +#ifndef TOOLS_ARCH_M32R_UAPI_ASM_MMAN_FIX_H +#define TOOLS_ARCH_M32R_UAPI_ASM_MMAN_FIX_H +#include <uapi/asm-generic/mman.h> +/* MAP_32BIT is undefined on m32r, fix it for perf */ +#define MAP_32BIT 0 +#endif diff --git a/tools/arch/microblaze/include/uapi/asm/mman.h b/tools/arch/microblaze/include/uapi/asm/mman.h new file mode 100644 index 000000000000..005cd50b50e1 --- /dev/null +++ b/tools/arch/microblaze/include/uapi/asm/mman.h @@ -0,0 +1,6 @@ +#ifndef TOOLS_ARCH_MICROBLAZE_UAPI_ASM_MMAN_FIX_H +#define TOOLS_ARCH_MICROBLAZE_UAPI_ASM_MMAN_FIX_H +#include <uapi/asm-generic/mman.h> +/* MAP_32BIT is undefined on microblaze, fix it for perf */ +#define MAP_32BIT 0 +#endif diff --git a/tools/arch/mips/include/uapi/asm/mman.h b/tools/arch/mips/include/uapi/asm/mman.h new file mode 100644 index 000000000000..c02052965d50 --- /dev/null +++ b/tools/arch/mips/include/uapi/asm/mman.h @@ -0,0 +1,46 @@ +#ifndef TOOLS_ARCH_MIPS_UAPI_ASM_MMAN_FIX_H +#define TOOLS_ARCH_MIPS_UAPI_ASM_MMAN_FIX_H +#define MADV_DODUMP 17 +#define MADV_DOFORK 11 +#define MADV_DONTDUMP 16 +#define MADV_DONTFORK 10 +#define MADV_DONTNEED 4 +#define MADV_FREE 8 +#define MADV_HUGEPAGE 14 +#define MADV_HWPOISON 100 +#define MADV_MERGEABLE 12 +#define MADV_NOHUGEPAGE 15 +#define MADV_NORMAL 0 +#define MADV_RANDOM 1 +#define MADV_REMOVE 9 +#define MADV_SEQUENTIAL 2 +#define MADV_UNMERGEABLE 13 +#define MADV_WILLNEED 3 +#define MAP_ANONYMOUS 0x0800 +#define MAP_DENYWRITE 0x2000 +#define MAP_EXECUTABLE 0x4000 +#define MAP_FILE 0 +#define MAP_FIXED 0x010 +#define MAP_GROWSDOWN 0x1000 +#define MAP_HUGETLB 0x80000 +#define MAP_LOCKED 0x8000 +#define MAP_NONBLOCK 0x20000 +#define MAP_NORESERVE 0x0400 +#define MAP_POPULATE 0x10000 +#define MAP_PRIVATE 0x002 +#define MAP_SHARED 0x001 +#define MAP_STACK 0x40000 +#define PROT_EXEC 0x04 +#define PROT_GROWSDOWN 0x01000000 +#define PROT_GROWSUP 0x02000000 +#define PROT_NONE 0x00 +#define PROT_READ 0x01 +#define PROT_SEM 0x10 +#define PROT_WRITE 0x02 +/* MADV_SOFT_OFFLINE is undefined on mips, fix it for perf */ +#define MADV_SOFT_OFFLINE 101 +/* MAP_32BIT is undefined on mips, fix it for perf */ +#define MAP_32BIT 0 +/* MAP_UNINITIALIZED is undefined on mips, fix it for perf */ +#define MAP_UNINITIALIZED 0 +#endif diff --git a/tools/arch/mn10300/include/uapi/asm/mman.h b/tools/arch/mn10300/include/uapi/asm/mman.h new file mode 100644 index 000000000000..c1ea36d83acc --- /dev/null +++ b/tools/arch/mn10300/include/uapi/asm/mman.h @@ -0,0 +1,6 @@ +#ifndef TOOLS_ARCH_MN10300_UAPI_ASM_MMAN_FIX_H +#define TOOLS_ARCH_MN10300_UAPI_ASM_MMAN_FIX_H +#include <uapi/asm-generic/mman.h> +/* MAP_32BIT is undefined on mn10300, fix it for perf */ +#define MAP_32BIT 0 +#endif diff --git a/tools/arch/parisc/include/uapi/asm/mman.h b/tools/arch/parisc/include/uapi/asm/mman.h new file mode 100644 index 000000000000..03d8d5b7ae7f --- /dev/null +++ b/tools/arch/parisc/include/uapi/asm/mman.h @@ -0,0 +1,47 @@ +#ifndef TOOLS_ARCH_PARISC_UAPI_ASM_MMAN_FIX_H +#define TOOLS_ARCH_PARISC_UAPI_ASM_MMAN_FIX_H +#define MADV_DODUMP 70 +#define MADV_DOFORK 11 +#define MADV_DONTDUMP 69 +#define MADV_DONTFORK 10 +#define MADV_DONTNEED 4 +#define MADV_FREE 8 +#define MADV_HUGEPAGE 67 +#define MADV_MERGEABLE 65 +#define MADV_NOHUGEPAGE 68 +#define MADV_NORMAL 0 +#define MADV_RANDOM 1 +#define MADV_REMOVE 9 +#define MADV_SEQUENTIAL 2 +#define MADV_UNMERGEABLE 66 +#define MADV_WILLNEED 3 +#define MAP_ANONYMOUS 0x10 +#define MAP_DENYWRITE 0x0800 +#define MAP_EXECUTABLE 0x1000 +#define MAP_FILE 0 +#define MAP_FIXED 0x04 +#define MAP_GROWSDOWN 0x8000 +#define MAP_HUGETLB 0x80000 +#define MAP_LOCKED 0x2000 +#define MAP_NONBLOCK 0x20000 +#define MAP_NORESERVE 0x4000 +#define MAP_POPULATE 0x10000 +#define MAP_PRIVATE 0x02 +#define MAP_SHARED 0x01 +#define MAP_STACK 0x40000 +#define PROT_EXEC 0x4 +#define PROT_GROWSDOWN 0x01000000 +#define PROT_GROWSUP 0x02000000 +#define PROT_NONE 0x0 +#define PROT_READ 0x1 +#define PROT_SEM 0x8 +#define PROT_WRITE 0x2 +/* MADV_HWPOISON is undefined on parisc, fix it for perf */ +#define MADV_HWPOISON 100 +/* MADV_SOFT_OFFLINE is undefined on parisc, fix it for perf */ +#define MADV_SOFT_OFFLINE 101 +/* MAP_32BIT is undefined on parisc, fix it for perf */ +#define MAP_32BIT 0 +/* MAP_UNINITIALIZED is undefined on parisc, fix it for perf */ +#define MAP_UNINITIALIZED 0 +#endif diff --git a/tools/arch/powerpc/include/uapi/asm/mman.h b/tools/arch/powerpc/include/uapi/asm/mman.h new file mode 100644 index 000000000000..761db43172fe --- /dev/null +++ b/tools/arch/powerpc/include/uapi/asm/mman.h @@ -0,0 +1,15 @@ +#ifndef TOOLS_ARCH_POWERPC_UAPI_ASM_MMAN_FIX_H +#define TOOLS_ARCH_POWERPC_UAPI_ASM_MMAN_FIX_H +#define MAP_DENYWRITE 0x0800 +#define MAP_EXECUTABLE 0x1000 +#define MAP_GROWSDOWN 0x0100 +#define MAP_HUGETLB 0x40000 +#define MAP_LOCKED 0x80 +#define MAP_NONBLOCK 0x10000 +#define MAP_NORESERVE 0x40 +#define MAP_POPULATE 0x8000 +#define MAP_STACK 0x20000 +#include <uapi/asm-generic/mman-common.h> +/* MAP_32BIT is undefined on powerpc, fix it for perf */ +#define MAP_32BIT 0 +#endif diff --git a/tools/arch/s390/include/uapi/asm/mman.h b/tools/arch/s390/include/uapi/asm/mman.h new file mode 100644 index 000000000000..b03dea9e1f56 --- /dev/null +++ b/tools/arch/s390/include/uapi/asm/mman.h @@ -0,0 +1,6 @@ +#ifndef TOOLS_ARCH_S390_UAPI_ASM_MMAN_FIX_H +#define TOOLS_ARCH_S390_UAPI_ASM_MMAN_FIX_H +#include <uapi/asm-generic/mman.h> +/* MAP_32BIT is undefined on s390, fix it for perf */ +#define MAP_32BIT 0 +#endif diff --git a/tools/arch/score/include/uapi/asm/mman.h b/tools/arch/score/include/uapi/asm/mman.h new file mode 100644 index 000000000000..2f8fb89944fd --- /dev/null +++ b/tools/arch/score/include/uapi/asm/mman.h @@ -0,0 +1,6 @@ +#ifndef TOOLS_ARCH_SCORE_UAPI_ASM_MMAN_FIX_H +#define TOOLS_ARCH_SCORE_UAPI_ASM_MMAN_FIX_H +#include <uapi/asm-generic/mman.h> +/* MAP_32BIT is undefined on score, fix it for perf */ +#define MAP_32BIT 0 +#endif diff --git a/tools/arch/sh/include/uapi/asm/mman.h b/tools/arch/sh/include/uapi/asm/mman.h new file mode 100644 index 000000000000..26504f6f060e --- /dev/null +++ b/tools/arch/sh/include/uapi/asm/mman.h @@ -0,0 +1,6 @@ +#ifndef TOOLS_ARCH_SH_UAPI_ASM_MMAN_FIX_H +#define TOOLS_ARCH_SH_UAPI_ASM_MMAN_FIX_H +#include <uapi/asm-generic/mman.h> +/* MAP_32BIT is undefined on sh, fix it for perf */ +#define MAP_32BIT 0 +#endif diff --git a/tools/arch/sparc/include/uapi/asm/mman.h b/tools/arch/sparc/include/uapi/asm/mman.h new file mode 100644 index 000000000000..8640525de991 --- /dev/null +++ b/tools/arch/sparc/include/uapi/asm/mman.h @@ -0,0 +1,15 @@ +#ifndef TOOLS_ARCH_SPARC_UAPI_ASM_MMAN_FIX_H +#define TOOLS_ARCH_SPARC_UAPI_ASM_MMAN_FIX_H +#define MAP_DENYWRITE 0x0800 +#define MAP_EXECUTABLE 0x1000 +#define MAP_GROWSDOWN 0x0200 +#define MAP_HUGETLB 0x40000 +#define MAP_LOCKED 0x100 +#define MAP_NONBLOCK 0x10000 +#define MAP_NORESERVE 0x40 +#define MAP_POPULATE 0x8000 +#define MAP_STACK 0x20000 +#include <uapi/asm-generic/mman-common.h> +/* MAP_32BIT is undefined on sparc, fix it for perf */ +#define MAP_32BIT 0 +#endif diff --git a/tools/arch/tile/include/uapi/asm/mman.h b/tools/arch/tile/include/uapi/asm/mman.h new file mode 100644 index 000000000000..7116c4b928b3 --- /dev/null +++ b/tools/arch/tile/include/uapi/asm/mman.h @@ -0,0 +1,15 @@ +#ifndef TOOLS_ARCH_TILE_UAPI_ASM_MMAN_FIX_H +#define TOOLS_ARCH_TILE_UAPI_ASM_MMAN_FIX_H +#define MAP_DENYWRITE 0x0800 +#define MAP_EXECUTABLE 0x1000 +#define MAP_GROWSDOWN 0x0100 +#define MAP_HUGETLB 0x4000 +#define MAP_LOCKED 0x0200 +#define MAP_NONBLOCK 0x0080 +#define MAP_NORESERVE 0x0400 +#define MAP_POPULATE 0x0040 +#define MAP_STACK MAP_GROWSDOWN +#include <uapi/asm-generic/mman-common.h> +/* MAP_32BIT is undefined on tile, fix it for perf */ +#define MAP_32BIT 0 +#endif diff --git a/tools/arch/x86/include/uapi/asm/mman.h b/tools/arch/x86/include/uapi/asm/mman.h new file mode 100644 index 000000000000..b73c1af8b1dd --- /dev/null +++ b/tools/arch/x86/include/uapi/asm/mman.h @@ -0,0 +1,5 @@ +#ifndef TOOLS_ARCH_X86_UAPI_ASM_MMAN_FIX_H +#define TOOLS_ARCH_X86_UAPI_ASM_MMAN_FIX_H +#define MAP_32BIT 0x40 +#include <uapi/asm-generic/mman.h> +#endif diff --git a/tools/arch/xtensa/include/uapi/asm/mman.h b/tools/arch/xtensa/include/uapi/asm/mman.h new file mode 100644 index 000000000000..4453195c450c --- /dev/null +++ b/tools/arch/xtensa/include/uapi/asm/mman.h @@ -0,0 +1,47 @@ +#ifndef TOOLS_ARCH_XTENSA_UAPI_ASM_MMAN_FIX_H +#define TOOLS_ARCH_XTENSA_UAPI_ASM_MMAN_FIX_H +#define MADV_DODUMP 17 +#define MADV_DOFORK 11 +#define MADV_DONTDUMP 16 +#define MADV_DONTFORK 10 +#define MADV_DONTNEED 4 +#define MADV_FREE 8 +#define MADV_HUGEPAGE 14 +#define MADV_MERGEABLE 12 +#define MADV_NOHUGEPAGE 15 +#define MADV_NORMAL 0 +#define MADV_RANDOM 1 +#define MADV_REMOVE 9 +#define MADV_SEQUENTIAL 2 +#define MADV_UNMERGEABLE 13 +#define MADV_WILLNEED 3 +#define MAP_ANONYMOUS 0x0800 +#define MAP_DENYWRITE 0x2000 +#define MAP_EXECUTABLE 0x4000 +#define MAP_FILE 0 +#define MAP_FIXED 0x010 +#define MAP_GROWSDOWN 0x1000 +#define MAP_HUGETLB 0x80000 +#define MAP_LOCKED 0x8000 +#define MAP_NONBLOCK 0x20000 +#define MAP_NORESERVE 0x0400 +#define MAP_POPULATE 0x10000 +#define MAP_PRIVATE 0x002 +#define MAP_SHARED 0x001 +#define MAP_STACK 0x40000 +#define PROT_EXEC 0x4 +#define PROT_GROWSDOWN 0x01000000 +#define PROT_GROWSUP 0x02000000 +#define PROT_NONE 0x0 +#define PROT_READ 0x1 +#define PROT_SEM 0x10 +#define PROT_WRITE 0x2 +/* MADV_HWPOISON is undefined on xtensa, fix it for perf */ +#define MADV_HWPOISON 100 +/* MADV_SOFT_OFFLINE is undefined on xtensa, fix it for perf */ +#define MADV_SOFT_OFFLINE 101 +/* MAP_32BIT is undefined on xtensa, fix it for perf */ +#define MAP_32BIT 0 +/* MAP_UNINITIALIZED is undefined on xtensa, fix it for perf */ +#define MAP_UNINITIALIZED 0 +#endif diff --git a/tools/include/linux/coresight-pmu.h b/tools/include/linux/coresight-pmu.h new file mode 100644 index 000000000000..7d410260661b --- /dev/null +++ b/tools/include/linux/coresight-pmu.h @@ -0,0 +1,39 @@ +/* + * Copyright(C) 2015 Linaro Limited. All rights reserved. + * Author: Mathieu Poirier <mathieu.poirier@linaro.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _LINUX_CORESIGHT_PMU_H +#define _LINUX_CORESIGHT_PMU_H + +#define CORESIGHT_ETM_PMU_NAME "cs_etm" +#define CORESIGHT_ETM_PMU_SEED 0x10 + +/* ETMv3.5/PTM's ETMCR config bit */ +#define ETM_OPT_CYCACC 12 +#define ETM_OPT_TS 28 + +static inline int coresight_get_trace_id(int cpu) +{ + /* + * A trace ID of value 0 is invalid, so let's start at some + * random value that fits in 7 bits and go from there. Since + * the common convention is to have data trace IDs be I(N) + 1, + * set instruction trace IDs as a function of the CPU number. + */ + return (CORESIGHT_ETM_PMU_SEED + (cpu * 2)); +} + +#endif diff --git a/tools/include/linux/time64.h b/tools/include/linux/time64.h new file mode 100644 index 000000000000..df9265483d65 --- /dev/null +++ b/tools/include/linux/time64.h @@ -0,0 +1,12 @@ +#ifndef _TOOLS_LINUX_TIME64_H +#define _TOOLS_LINUX_TIME64_H + +#define MSEC_PER_SEC 1000L +#define USEC_PER_MSEC 1000L +#define NSEC_PER_USEC 1000L +#define NSEC_PER_MSEC 1000000L +#define USEC_PER_SEC 1000000L +#define NSEC_PER_SEC 1000000000L +#define FSEC_PER_SEC 1000000000000000LL + +#endif /* _LINUX_TIME64_H */ diff --git a/tools/include/uapi/asm-generic/mman-common.h b/tools/include/uapi/asm-generic/mman-common.h new file mode 100644 index 000000000000..58274382a616 --- /dev/null +++ b/tools/include/uapi/asm-generic/mman-common.h @@ -0,0 +1,75 @@ +#ifndef __ASM_GENERIC_MMAN_COMMON_H +#define __ASM_GENERIC_MMAN_COMMON_H + +/* + Author: Michael S. Tsirkin <mst@mellanox.co.il>, Mellanox Technologies Ltd. + Based on: asm-xxx/mman.h +*/ + +#define PROT_READ 0x1 /* page can be read */ +#define PROT_WRITE 0x2 /* page can be written */ +#define PROT_EXEC 0x4 /* page can be executed */ +#define PROT_SEM 0x8 /* page may be used for atomic ops */ +#define PROT_NONE 0x0 /* page can not be accessed */ +#define PROT_GROWSDOWN 0x01000000 /* mprotect flag: extend change to start of growsdown vma */ +#define PROT_GROWSUP 0x02000000 /* mprotect flag: extend change to end of growsup vma */ + +#define MAP_SHARED 0x01 /* Share changes */ +#define MAP_PRIVATE 0x02 /* Changes are private */ +#define MAP_TYPE 0x0f /* Mask for type of mapping */ +#define MAP_FIXED 0x10 /* Interpret addr exactly */ +#define MAP_ANONYMOUS 0x20 /* don't use a file */ +#ifdef CONFIG_MMAP_ALLOW_UNINITIALIZED +# define MAP_UNINITIALIZED 0x4000000 /* For anonymous mmap, memory could be uninitialized */ +#else +# define MAP_UNINITIALIZED 0x0 /* Don't support this flag */ +#endif + +/* + * Flags for mlock + */ +#define MLOCK_ONFAULT 0x01 /* Lock pages in range after they are faulted in, do not prefault */ + +#define MS_ASYNC 1 /* sync memory asynchronously */ +#define MS_INVALIDATE 2 /* invalidate the caches */ +#define MS_SYNC 4 /* synchronous memory sync */ + +#define MADV_NORMAL 0 /* no further special treatment */ +#define MADV_RANDOM 1 /* expect random page references */ +#define MADV_SEQUENTIAL 2 /* expect sequential page references */ +#define MADV_WILLNEED 3 /* will need these pages */ +#define MADV_DONTNEED 4 /* don't need these pages */ + +/* common parameters: try to keep these consistent across architectures */ +#define MADV_FREE 8 /* free pages only if memory pressure */ +#define MADV_REMOVE 9 /* remove these pages & resources */ +#define MADV_DONTFORK 10 /* don't inherit across fork */ +#define MADV_DOFORK 11 /* do inherit across fork */ +#define MADV_HWPOISON 100 /* poison a page for testing */ +#define MADV_SOFT_OFFLINE 101 /* soft offline page for testing */ + +#define MADV_MERGEABLE 12 /* KSM may merge identical pages */ +#define MADV_UNMERGEABLE 13 /* KSM may not merge identical pages */ + +#define MADV_HUGEPAGE 14 /* Worth backing with hugepages */ +#define MADV_NOHUGEPAGE 15 /* Not worth backing with hugepages */ + +#define MADV_DONTDUMP 16 /* Explicity exclude from the core dump, + overrides the coredump filter bits */ +#define MADV_DODUMP 17 /* Clear the MADV_DONTDUMP flag */ + +/* compatibility flags */ +#define MAP_FILE 0 + +/* + * When MAP_HUGETLB is set bits [26:31] encode the log2 of the huge page size. + * This gives us 6 bits, which is enough until someone invents 128 bit address + * spaces. + * + * Assume these are all power of twos. + * When 0 use the default page size. + */ +#define MAP_HUGE_SHIFT 26 +#define MAP_HUGE_MASK 0x3f + +#endif /* __ASM_GENERIC_MMAN_COMMON_H */ diff --git a/tools/include/uapi/asm-generic/mman.h b/tools/include/uapi/asm-generic/mman.h new file mode 100644 index 000000000000..10fa7857777f --- /dev/null +++ b/tools/include/uapi/asm-generic/mman.h @@ -0,0 +1,22 @@ +#ifndef __ASM_GENERIC_MMAN_H +#define __ASM_GENERIC_MMAN_H + +#include <uapi/asm-generic/mman-common.h> + +#define MAP_GROWSDOWN 0x0100 /* stack-like segment */ +#define MAP_DENYWRITE 0x0800 /* ETXTBSY */ +#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */ +#define MAP_LOCKED 0x2000 /* pages are locked */ +#define MAP_NORESERVE 0x4000 /* don't check for reservations */ +#define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */ +#define MAP_NONBLOCK 0x10000 /* do not block on IO */ +#define MAP_STACK 0x20000 /* give out an address that is best suited for process/thread stacks */ +#define MAP_HUGETLB 0x40000 /* create a huge page mapping */ + +/* Bits [26:31] are reserved, see mman-common.h for MAP_HUGETLB usage */ + +#define MCL_CURRENT 1 /* lock all current mappings */ +#define MCL_FUTURE 2 /* lock all future mappings */ +#define MCL_ONFAULT 4 /* lock all pages that are faulted in */ + +#endif /* __ASM_GENERIC_MMAN_H */ diff --git a/tools/include/uapi/linux/mman.h b/tools/include/uapi/linux/mman.h new file mode 100644 index 000000000000..81d8edf11789 --- /dev/null +++ b/tools/include/uapi/linux/mman.h @@ -0,0 +1,13 @@ +#ifndef _UAPI_LINUX_MMAN_H +#define _UAPI_LINUX_MMAN_H + +#include <uapi/asm/mman.h> + +#define MREMAP_MAYMOVE 1 +#define MREMAP_FIXED 2 + +#define OVERCOMMIT_GUESS 0 +#define OVERCOMMIT_ALWAYS 1 +#define OVERCOMMIT_NEVER 2 + +#endif /* _UAPI_LINUX_MMAN_H */ diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c index ba7094b945ff..f99f49e4a31e 100644 --- a/tools/lib/api/fs/fs.c +++ b/tools/lib/api/fs/fs.c @@ -34,6 +34,10 @@ #define TRACEFS_MAGIC 0x74726163 #endif +#ifndef HUGETLBFS_MAGIC +#define HUGETLBFS_MAGIC 0x958458f6 +#endif + static const char * const sysfs__fs_known_mountpoints[] = { "/sys", 0, @@ -67,6 +71,10 @@ static const char * const tracefs__known_mountpoints[] = { 0, }; +static const char * const hugetlbfs__known_mountpoints[] = { + 0, +}; + struct fs { const char *name; const char * const *mounts; @@ -80,6 +88,7 @@ enum { FS__PROCFS = 1, FS__DEBUGFS = 2, FS__TRACEFS = 3, + FS__HUGETLBFS = 4, }; #ifndef TRACEFS_MAGIC @@ -107,6 +116,11 @@ static struct fs fs__entries[] = { .mounts = tracefs__known_mountpoints, .magic = TRACEFS_MAGIC, }, + [FS__HUGETLBFS] = { + .name = "hugetlbfs", + .mounts = hugetlbfs__known_mountpoints, + .magic = HUGETLBFS_MAGIC, + }, }; static bool fs__read_mounts(struct fs *fs) @@ -265,6 +279,7 @@ FS(sysfs, FS__SYSFS); FS(procfs, FS__PROCFS); FS(debugfs, FS__DEBUGFS); FS(tracefs, FS__TRACEFS); +FS(hugetlbfs, FS__HUGETLBFS); int filename__read_int(const char *filename, int *value) { diff --git a/tools/lib/api/fs/fs.h b/tools/lib/api/fs/fs.h index 16c9c2ed7c5b..a63269f5d20c 100644 --- a/tools/lib/api/fs/fs.h +++ b/tools/lib/api/fs/fs.h @@ -21,6 +21,7 @@ FS(sysfs) FS(procfs) FS(debugfs) FS(tracefs) +FS(hugetlbfs) #undef FS diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt index 15949e2a7805..cb081ac59fd1 100644 --- a/tools/perf/Documentation/perf-config.txt +++ b/tools/perf/Documentation/perf-config.txt @@ -110,6 +110,14 @@ Given a $HOME/.perfconfig like this: order = caller sort-key = function + [report] + # Defaults + sort-order = comm,dso,symbol + percent-limit = 0 + queue-size = 0 + children = true + group = true + Variables ~~~~~~~~~ @@ -382,6 +390,10 @@ call-graph.*:: histogram entry. Default is 0 which means no limitation. report.*:: + report.sort_order:: + Allows changing the default sort order from "comm,dso,symbol" to + some other default, for instance "sym,dso" may be more fitting for + kernel developers. report.percent-limit:: This one is mostly the same as call-graph.threshold but works for histogram entries. Entries having an overhead lower than this diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index b303bcdd8ed1..e6c9902c6d82 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt @@ -21,6 +21,8 @@ or 'perf probe' [options] --vars='PROBEPOINT' or 'perf probe' [options] --funcs +or +'perf probe' [options] --definition='PROBE' [...] DESCRIPTION ----------- @@ -34,6 +36,8 @@ OPTIONS -k:: --vmlinux=PATH:: Specify vmlinux path which has debuginfo (Dwarf binary). + Only when using this with --definition, you can give an offline + vmlinux file. -m:: --module=MODNAME|PATH:: @@ -96,6 +100,11 @@ OPTIONS can also list functions in a user space executable / shared library. This also can accept a FILTER rule argument. +-D:: +--definition=:: + Show trace-event definition converted from given probe-event instead + of write it into tracing/[k,u]probe_events. + --filter=FILTER:: (Only for --vars and --funcs) Set filter. FILTER is a combination of glob pattern, see FILTER PATTERN for detail. @@ -176,13 +185,12 @@ Each probe argument follows below syntax. 'NAME' specifies the name of this argument (optional). You can use the name of local variable, local data structure member (e.g. var->field, var.field2), local array with fixed index (e.g. array[1], var->array[0], var->pointer[2]), or kprobe-tracer argument format (e.g. $retval, %ax, etc). Note that the name of this argument will be set as the last member name if you specify a local data structure member (e.g. field2 for 'var->field1.field2'.) '$vars' and '$params' special arguments are also available for NAME, '$vars' is expanded to the local variables (including function parameters) which can access at given probe point. '$params' is expanded to only the function parameters. -'TYPE' casts the type of this argument (optional). If omitted, perf probe automatically set the type based on debuginfo. Currently, basic types (u8/u16/u32/u64/s8/s16/s32/s64), signedness casting (u/s), "string" and bitfield are supported. (see TYPES for detail) - +'TYPE' casts the type of this argument (optional). If omitted, perf probe automatically set the type based on debuginfo (*). Currently, basic types (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal integers (x/x8/x16/x32/x64), signedness casting (u/s), "string" and bitfield are supported. (see TYPES for detail) On x86 systems %REG is always the short form of the register: for example %AX. %RAX or %EAX is not valid. TYPES ----- -Basic types (u8/u16/u32/u64/s8/s16/s32/s64) are integer types. Prefix 's' and 'u' means those types are signed and unsigned respectively. Traced arguments are shown in decimal (signed) or hex (unsigned). You can also use 's' or 'u' to specify only signedness and leave its size auto-detected by perf probe. +Basic types (u8/u16/u32/u64/s8/s16/s32/s64) and hexadecimal integers (x8/x16/x32/x64) are integer types. Prefix 's' and 'u' means those types are signed and unsigned respectively, and 'x' means that is shown in hexadecimal format. Traced arguments are shown in decimal (sNN/uNN) or hex (xNN). You can also use 's' or 'u' to specify only signedness and leave its size auto-detected by perf probe. Moreover, you can use 'x' to explicitly specify to be shown in hexadecimal (the size is also auto-detected). String type is a special type, which fetches a "null-terminated" string from kernel space. This means it will fail and store NULL if the string container has been paged out. You can specify 'string' type only for the local variable or structure member which is an array of or a pointer to 'char' or 'unsigned char' type. Bitfield is another special type, which takes 3 parameters, bit-width, bit-offset, and container-size (usually 32). The syntax is; diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 379a2bed07c0..1a24f4d64328 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -60,6 +60,18 @@ OPTIONS Note: If user explicitly sets options which conflict with the params, the value set by the params will be overridden. + Also not defined in .../<pmu>/format/* are PMU driver specific + configuration parameters. Any configuration parameter preceded by + the letter '@' is not interpreted in user space and sent down directly + to the PMU driver. For example: + + perf record -e some_event/@cfg1,@cfg2=config/ ... + + will see 'cfg1' and 'cfg2=config' pushed to the PMU driver associated + with the event for further processing. There is no restriction on + what the configuration parameters are, as long as their semantic is + understood and supported by the PMU driver. + - a hardware breakpoint event in the form of '\mem:addr[/len][:access]' where addr is the address in memory you want to break in. Access is the memory access type (read, write, execute) it can diff --git a/tools/perf/Documentation/perfconfig.example b/tools/perf/Documentation/perfconfig.example index 1d8d5bc4cd2d..2b477c1d1efe 100644 --- a/tools/perf/Documentation/perfconfig.example +++ b/tools/perf/Documentation/perfconfig.example @@ -27,3 +27,12 @@ use_offset = true jump_arrows = true show_nr_jumps = false + +[report] + + # Defaults + sort-order = comm,dso,symbol + percent-limit = 0 + queue-size = 0 + children = true + group = true diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index ad2534df4ba6..0bda2cca2b3a 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST @@ -60,14 +60,18 @@ tools/include/asm-generic/bitops.h tools/include/linux/atomic.h tools/include/linux/bitops.h tools/include/linux/compiler.h +tools/include/linux/coresight-pmu.h tools/include/linux/filter.h tools/include/linux/hash.h tools/include/linux/kernel.h tools/include/linux/list.h tools/include/linux/log2.h +tools/include/uapi/asm-generic/mman-common.h +tools/include/uapi/asm-generic/mman.h tools/include/uapi/linux/bpf.h tools/include/uapi/linux/bpf_common.h tools/include/uapi/linux/hw_breakpoint.h +tools/include/uapi/linux/mman.h tools/include/uapi/linux/perf_event.h tools/include/linux/poison.h tools/include/linux/rbtree.h @@ -77,4 +81,6 @@ tools/include/linux/stringify.h tools/include/linux/types.h tools/include/linux/err.h tools/include/linux/bitmap.h +tools/include/linux/time64.h +tools/arch/*/include/uapi/asm/mman.h tools/arch/*/include/uapi/asm/perf_regs.h diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 2d9087501633..d710db16b963 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -165,7 +165,7 @@ SUBCMD_DIR = $(srctree)/tools/lib/subcmd/ # non-config cases config := 1 -NON_CONFIG_TARGETS := clean TAGS tags cscope help +NON_CONFIG_TARGETS := clean TAGS tags cscope help install-doc ifdef MAKECMDGOALS ifeq ($(filter-out $(NON_CONFIG_TARGETS),$(MAKECMDGOALS)),) @@ -429,6 +429,18 @@ $(PERF_IN): prepare FORCE @(test -f ../../include/asm-generic/bitops/fls64.h && ( \ (diff -B ../include/asm-generic/bitops/fls64.h ../../include/asm-generic/bitops/fls64.h >/dev/null) \ || echo "Warning: tools/include/asm-generic/bitops/fls64.h differs from kernel" >&2 )) || true + @(test -f ../../include/linux/coresight-pmu.h && ( \ + (diff -B ../include/linux/coresight-pmu.h ../../include/linux/coresight-pmu.h >/dev/null) \ + || echo "Warning: tools/include/linux/coresight-pmu.h differs from kernel" >&2 )) || true + @(test -f ../../include/uapi/asm-generic/mman-common.h && ( \ + (diff -B ../include/uapi/asm-generic/mman-common.h ../../include/uapi/asm-generic/mman-common.h >/dev/null) \ + || echo "Warning: tools/include/uapi/asm-generic/mman-common.h differs from kernel" >&2 )) || true + @(test -f ../../include/uapi/asm-generic/mman.h && ( \ + (diff -B -I "^#include <\(uapi/\)*asm-generic/mman-common.h>$$" ../include/uapi/asm-generic/mman.h ../../include/uapi/asm-generic/mman.h >/dev/null) \ + || echo "Warning: tools/include/uapi/asm-generic/mman.h differs from kernel" >&2 )) || true + @(test -f ../../include/uapi/linux/mman.h && ( \ + (diff -B -I "^#include <\(uapi/\)*asm/mman.h>$$" ../include/uapi/linux/mman.h ../../include/uapi/linux/mman.h >/dev/null) \ + || echo "Warning: tools/include/uapi/linux/mman.h differs from kernel" >&2 )) || true $(Q)$(MAKE) $(build)=perf $(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(LIBTRACEEVENT_DYNAMIC_LIST) diff --git a/tools/perf/arch/arm/include/dwarf-regs-table.h b/tools/perf/arch/arm/include/dwarf-regs-table.h new file mode 100644 index 000000000000..f298d034c37b --- /dev/null +++ b/tools/perf/arch/arm/include/dwarf-regs-table.h @@ -0,0 +1,9 @@ +#ifdef DEFINE_DWARF_REGSTR_TABLE +/* This is included in perf/util/dwarf-regs.c */ + +static const char * const arm_regstr_tbl[] = { + "%r0", "%r1", "%r2", "%r3", "%r4", + "%r5", "%r6", "%r7", "%r8", "%r9", "%r10", + "%fp", "%ip", "%sp", "%lr", "%pc", +}; +#endif diff --git a/tools/perf/arch/arm64/include/dwarf-regs-table.h b/tools/perf/arch/arm64/include/dwarf-regs-table.h new file mode 100644 index 000000000000..26759363f921 --- /dev/null +++ b/tools/perf/arch/arm64/include/dwarf-regs-table.h @@ -0,0 +1,13 @@ +#ifdef DEFINE_DWARF_REGSTR_TABLE +/* This is included in perf/util/dwarf-regs.c */ + +static const char * const aarch64_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", + "%lr", "%sp", +}; +#endif diff --git a/tools/perf/arch/powerpc/include/dwarf-regs-table.h b/tools/perf/arch/powerpc/include/dwarf-regs-table.h new file mode 100644 index 000000000000..db4730f5585c --- /dev/null +++ b/tools/perf/arch/powerpc/include/dwarf-regs-table.h @@ -0,0 +1,27 @@ +#ifdef DEFINE_DWARF_REGSTR_TABLE +/* This is included in perf/util/dwarf-regs.c */ + +/* + * Reference: + * http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html + * http://refspecs.linux-foundation.org/elf/elfspec_ppc.pdf + */ +#define REG_DWARFNUM_NAME(reg, idx) [idx] = "%" #reg + +static const char * const powerpc_regstr_tbl[] = { + "%gpr0", "%gpr1", "%gpr2", "%gpr3", "%gpr4", + "%gpr5", "%gpr6", "%gpr7", "%gpr8", "%gpr9", + "%gpr10", "%gpr11", "%gpr12", "%gpr13", "%gpr14", + "%gpr15", "%gpr16", "%gpr17", "%gpr18", "%gpr19", + "%gpr20", "%gpr21", "%gpr22", "%gpr23", "%gpr24", + "%gpr25", "%gpr26", "%gpr27", "%gpr28", "%gpr29", + "%gpr30", "%gpr31", + REG_DWARFNUM_NAME(msr, 66), + REG_DWARFNUM_NAME(ctr, 109), + REG_DWARFNUM_NAME(link, 108), + REG_DWARFNUM_NAME(xer, 101), + REG_DWARFNUM_NAME(dar, 119), + REG_DWARFNUM_NAME(dsisr, 118), +}; + +#endif diff --git a/tools/perf/arch/powerpc/util/sym-handling.c b/tools/perf/arch/powerpc/util/sym-handling.c index 35745a733100..ed9d5d15d5b6 100644 --- a/tools/perf/arch/powerpc/util/sym-handling.c +++ b/tools/perf/arch/powerpc/util/sym-handling.c @@ -108,7 +108,7 @@ void arch__post_process_probe_trace_events(struct perf_probe_event *pev, int i = 0; map = get_target_map(pev->target, pev->uprobes); - if (!map || map__load(map, NULL) < 0) + if (!map || map__load(map) < 0) return; for (i = 0; i < ntevs; i++) { diff --git a/tools/perf/arch/s390/include/dwarf-regs-table.h b/tools/perf/arch/s390/include/dwarf-regs-table.h new file mode 100644 index 000000000000..9da74a933bd6 --- /dev/null +++ b/tools/perf/arch/s390/include/dwarf-regs-table.h @@ -0,0 +1,8 @@ +#ifdef DEFINE_DWARF_REGSTR_TABLE +/* This is included in perf/util/dwarf-regs.c */ + +static const char * const s390_regstr_tbl[] = { + "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7", + "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", +}; +#endif diff --git a/tools/perf/arch/sh/include/dwarf-regs-table.h b/tools/perf/arch/sh/include/dwarf-regs-table.h new file mode 100644 index 000000000000..3a2deaf3dab4 --- /dev/null +++ b/tools/perf/arch/sh/include/dwarf-regs-table.h @@ -0,0 +1,25 @@ +#ifdef DEFINE_DWARF_REGSTR_TABLE +/* This is included in perf/util/dwarf-regs.c */ + +const char * const sh_regstr_tbl[] = { + "r0", + "r1", + "r2", + "r3", + "r4", + "r5", + "r6", + "r7", + "r8", + "r9", + "r10", + "r11", + "r12", + "r13", + "r14", + "r15", + "pc", + "pr", +}; + +#endif diff --git a/tools/perf/arch/sparc/include/dwarf-regs-table.h b/tools/perf/arch/sparc/include/dwarf-regs-table.h new file mode 100644 index 000000000000..12c07619002c --- /dev/null +++ b/tools/perf/arch/sparc/include/dwarf-regs-table.h @@ -0,0 +1,18 @@ +#ifdef DEFINE_DWARF_REGSTR_TABLE +/* This is included in perf/util/dwarf-regs.c */ + +static const char * const sparc_regstr_tbl[] = { + "%g0", "%g1", "%g2", "%g3", "%g4", "%g5", "%g6", "%g7", + "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%sp", "%o7", + "%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", "%l7", + "%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%fp", "%i7", + "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7", + "%f8", "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15", + "%f16", "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23", + "%f24", "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31", + "%f32", "%f33", "%f34", "%f35", "%f36", "%f37", "%f38", "%f39", + "%f40", "%f41", "%f42", "%f43", "%f44", "%f45", "%f46", "%f47", + "%f48", "%f49", "%f50", "%f51", "%f52", "%f53", "%f54", "%f55", + "%f56", "%f57", "%f58", "%f59", "%f60", "%f61", "%f62", "%f63", +}; +#endif diff --git a/tools/perf/arch/x86/include/dwarf-regs-table.h b/tools/perf/arch/x86/include/dwarf-regs-table.h new file mode 100644 index 000000000000..9b5e5cbb4209 --- /dev/null +++ b/tools/perf/arch/x86/include/dwarf-regs-table.h @@ -0,0 +1,14 @@ +#ifdef DEFINE_DWARF_REGSTR_TABLE +/* This is included in perf/util/dwarf-regs.c */ + +static const char * const x86_32_regstr_tbl[] = { + "%ax", "%cx", "%dx", "%bx", "$stack",/* Stack address instead of %sp */ + "%bp", "%si", "%di", +}; + +static const char * const x86_64_regstr_tbl[] = { + "%ax", "%dx", "%cx", "%bx", "%si", "%di", + "%bp", "%sp", "%r8", "%r9", "%r10", "%r11", + "%r12", "%r13", "%r14", "%r15", +}; +#endif diff --git a/tools/perf/arch/xtensa/include/dwarf-regs-table.h b/tools/perf/arch/xtensa/include/dwarf-regs-table.h new file mode 100644 index 000000000000..aa0444a33fe6 --- /dev/null +++ b/tools/perf/arch/xtensa/include/dwarf-regs-table.h @@ -0,0 +1,8 @@ +#ifdef DEFINE_DWARF_REGSTR_TABLE +/* This is included in perf/util/dwarf-regs.c */ + +static const char * const xtensa_regstr_tbl[] = { + "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", + "a8", "a9", "a10", "a11", "a12", "a13", "a14", "a15", +}; +#endif diff --git a/tools/perf/bench/futex-requeue.c b/tools/perf/bench/futex-requeue.c index f96e22ed9f87..2b9705a8734c 100644 --- a/tools/perf/bench/futex-requeue.c +++ b/tools/perf/bench/futex-requeue.c @@ -16,6 +16,7 @@ #include <subcmd/parse-options.h> #include <linux/compiler.h> #include <linux/kernel.h> +#include <linux/time64.h> #include <errno.h> #include "bench.h" #include "futex.h" @@ -62,7 +63,7 @@ static void print_summary(void) printf("Requeued %d of %d threads in %.4f ms (+-%.2f%%)\n", requeued_avg, nthreads, - requeuetime_avg/1e3, + requeuetime_avg / USEC_PER_MSEC, rel_stddev_stats(requeuetime_stddev, requeuetime_avg)); } @@ -184,7 +185,7 @@ int bench_futex_requeue(int argc, const char **argv, if (!silent) { printf("[Run %d]: Requeued %d of %d threads in %.4f ms\n", - j + 1, nrequeued, nthreads, runtime.tv_usec/1e3); + j + 1, nrequeued, nthreads, runtime.tv_usec / (double)USEC_PER_MSEC); } /* everybody should be blocked on futex2, wake'em up */ diff --git a/tools/perf/bench/futex-wake-parallel.c b/tools/perf/bench/futex-wake-parallel.c index 4a2ecd7438ca..2c8fa67ad537 100644 --- a/tools/perf/bench/futex-wake-parallel.c +++ b/tools/perf/bench/futex-wake-parallel.c @@ -15,6 +15,7 @@ #include <subcmd/parse-options.h> #include <linux/compiler.h> #include <linux/kernel.h> +#include <linux/time64.h> #include <errno.h> #include "bench.h" #include "futex.h" @@ -156,7 +157,7 @@ static void print_run(struct thread_data *waking_worker, unsigned int run_num) printf("[Run %d]: Avg per-thread latency (waking %d/%d threads) " "in %.4f ms (+-%.2f%%)\n", run_num + 1, wakeup_avg, - nblocked_threads, waketime_avg/1e3, + nblocked_threads, waketime_avg / USEC_PER_MSEC, rel_stddev_stats(waketime_stddev, waketime_avg)); } @@ -172,7 +173,7 @@ static void print_summary(void) printf("Avg per-thread latency (waking %d/%d threads) in %.4f ms (+-%.2f%%)\n", wakeup_avg, nblocked_threads, - waketime_avg/1e3, + waketime_avg / USEC_PER_MSEC, rel_stddev_stats(waketime_stddev, waketime_avg)); } diff --git a/tools/perf/bench/futex-wake.c b/tools/perf/bench/futex-wake.c index 87d8f4f292d9..e246b1b8388a 100644 --- a/tools/perf/bench/futex-wake.c +++ b/tools/perf/bench/futex-wake.c @@ -16,6 +16,7 @@ #include <subcmd/parse-options.h> #include <linux/compiler.h> #include <linux/kernel.h> +#include <linux/time64.h> #include <errno.h> #include "bench.h" #include "futex.h" @@ -81,7 +82,7 @@ static void print_summary(void) printf("Wokeup %d of %d threads in %.4f ms (+-%.2f%%)\n", wakeup_avg, nthreads, - waketime_avg/1e3, + waketime_avg / USEC_PER_MSEC, rel_stddev_stats(waketime_stddev, waketime_avg)); } @@ -182,7 +183,7 @@ int bench_futex_wake(int argc, const char **argv, if (!silent) { printf("[Run %d]: Wokeup %d of %d threads in %.4f ms\n", - j + 1, nwoken, nthreads, runtime.tv_usec/1e3); + j + 1, nwoken, nthreads, runtime.tv_usec / (double)USEC_PER_MSEC); } for (i = 0; i < nthreads; i++) { diff --git a/tools/perf/bench/mem-functions.c b/tools/perf/bench/mem-functions.c index 2b54d0f2672a..c684910e5a48 100644 --- a/tools/perf/bench/mem-functions.c +++ b/tools/perf/bench/mem-functions.c @@ -21,6 +21,7 @@ #include <string.h> #include <sys/time.h> #include <errno.h> +#include <linux/time64.h> #define K 1024 @@ -89,7 +90,7 @@ static u64 get_cycles(void) static double timeval2double(struct timeval *ts) { - return (double)ts->tv_sec + (double)ts->tv_usec / (double)1000000; + return (double)ts->tv_sec + (double)ts->tv_usec / (double)USEC_PER_SEC; } #define print_bps(x) do { \ diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c index f7f530081aa9..8efe904e486b 100644 --- a/tools/perf/bench/numa.c +++ b/tools/perf/bench/numa.c @@ -30,6 +30,7 @@ #include <sys/wait.h> #include <sys/prctl.h> #include <sys/types.h> +#include <linux/time64.h> #include <numa.h> #include <numaif.h> @@ -1004,7 +1005,7 @@ static void calc_convergence(double runtime_ns_max, double *convergence) if (strong && process_groups == g->p.nr_proc) { if (!*convergence) { *convergence = runtime_ns_max; - tprintf(" (%6.1fs converged)\n", *convergence/1e9); + tprintf(" (%6.1fs converged)\n", *convergence / NSEC_PER_SEC); if (g->p.measure_convergence) { g->all_converged = true; g->stop_work = true; @@ -1012,7 +1013,7 @@ static void calc_convergence(double runtime_ns_max, double *convergence) } } else { if (*convergence) { - tprintf(" (%6.1fs de-converged)", runtime_ns_max/1e9); + tprintf(" (%6.1fs de-converged)", runtime_ns_max / NSEC_PER_SEC); *convergence = 0; } tprintf("\n"); @@ -1022,7 +1023,7 @@ static void calc_convergence(double runtime_ns_max, double *convergence) static void show_summary(double runtime_ns_max, int l, double *convergence) { tprintf("\r # %5.1f%% [%.1f mins]", - (double)(l+1)/g->p.nr_loops*100.0, runtime_ns_max/1e9 / 60.0); + (double)(l+1)/g->p.nr_loops*100.0, runtime_ns_max / NSEC_PER_SEC / 60.0); calc_convergence(runtime_ns_max, convergence); @@ -1179,8 +1180,8 @@ static void *worker_thread(void *__tdata) if (details >= 3) { timersub(&stop, &start, &diff); - runtime_ns_max = diff.tv_sec * 1000000000; - runtime_ns_max += diff.tv_usec * 1000; + runtime_ns_max = diff.tv_sec * NSEC_PER_SEC; + runtime_ns_max += diff.tv_usec * NSEC_PER_USEC; if (details >= 0) { printf(" #%2d / %2d: %14.2lf nsecs/op [val: %016"PRIx64"]\n", @@ -1192,23 +1193,23 @@ static void *worker_thread(void *__tdata) continue; timersub(&stop, &start0, &diff); - runtime_ns_max = diff.tv_sec * 1000000000ULL; - runtime_ns_max += diff.tv_usec * 1000ULL; + runtime_ns_max = diff.tv_sec * NSEC_PER_SEC; + runtime_ns_max += diff.tv_usec * NSEC_PER_USEC; show_summary(runtime_ns_max, l, &convergence); } gettimeofday(&stop, NULL); timersub(&stop, &start0, &diff); - td->runtime_ns = diff.tv_sec * 1000000000ULL; - td->runtime_ns += diff.tv_usec * 1000ULL; - td->speed_gbs = bytes_done / (td->runtime_ns / 1e9) / 1e9; + td->runtime_ns = diff.tv_sec * NSEC_PER_SEC; + td->runtime_ns += diff.tv_usec * NSEC_PER_USEC; + td->speed_gbs = bytes_done / (td->runtime_ns / NSEC_PER_SEC) / 1e9; getrusage(RUSAGE_THREAD, &rusage); - td->system_time_ns = rusage.ru_stime.tv_sec * 1000000000ULL; - td->system_time_ns += rusage.ru_stime.tv_usec * 1000ULL; - td->user_time_ns = rusage.ru_utime.tv_sec * 1000000000ULL; - td->user_time_ns += rusage.ru_utime.tv_usec * 1000ULL; + td->system_time_ns = rusage.ru_stime.tv_sec * NSEC_PER_SEC; + td->system_time_ns += rusage.ru_stime.tv_usec * NSEC_PER_USEC; + td->user_time_ns = rusage.ru_utime.tv_sec * NSEC_PER_SEC; + td->user_time_ns += rusage.ru_utime.tv_usec * NSEC_PER_USEC; free_data(thread_data, g->p.bytes_thread); @@ -1469,7 +1470,7 @@ static int __bench_numa(const char *name) } /* Wait for all the threads to start up: */ while (g->nr_tasks_started != g->p.nr_tasks) - usleep(1000); + usleep(USEC_PER_MSEC); BUG_ON(g->nr_tasks_started != g->p.nr_tasks); @@ -1488,9 +1489,9 @@ static int __bench_numa(const char *name) timersub(&stop, &start, &diff); - startup_sec = diff.tv_sec * 1000000000.0; - startup_sec += diff.tv_usec * 1000.0; - startup_sec /= 1e9; + startup_sec = diff.tv_sec * NSEC_PER_SEC; + startup_sec += diff.tv_usec * NSEC_PER_USEC; + startup_sec /= NSEC_PER_SEC; tprintf(" threads initialized in %.6f seconds.\n", startup_sec); tprintf(" #\n"); @@ -1529,14 +1530,14 @@ static int __bench_numa(const char *name) tprintf("\n ###\n"); tprintf("\n"); - runtime_sec_max = diff.tv_sec * 1000000000.0; - runtime_sec_max += diff.tv_usec * 1000.0; - runtime_sec_max /= 1e9; + runtime_sec_max = diff.tv_sec * NSEC_PER_SEC; + runtime_sec_max += diff.tv_usec * NSEC_PER_USEC; + runtime_sec_max /= NSEC_PER_SEC; - runtime_sec_min = runtime_ns_min/1e9; + runtime_sec_min = runtime_ns_min / NSEC_PER_SEC; bytes = g->bytes_done; - runtime_avg = (double)runtime_ns_sum / g->p.nr_tasks / 1e9; + runtime_avg = (double)runtime_ns_sum / g->p.nr_tasks / NSEC_PER_SEC; if (g->p.measure_convergence) { print_res(name, runtime_sec_max, @@ -1562,7 +1563,7 @@ static int __bench_numa(const char *name) print_res(name, bytes / 1e9, "GB,", "data-total", "GB data processed, total"); - print_res(name, runtime_sec_max * 1e9 / (bytes / g->p.nr_tasks), + print_res(name, runtime_sec_max * NSEC_PER_SEC / (bytes / g->p.nr_tasks), "nsecs,", "runtime/byte/thread","nsecs/byte/thread runtime"); print_res(name, bytes / g->p.nr_tasks / 1e9 / runtime_sec_max, @@ -1581,9 +1582,9 @@ static int __bench_numa(const char *name) snprintf(tname, 32, "process%d:thread%d", p, t); print_res(tname, td->speed_gbs, "GB/sec", "thread-speed", "GB/sec/thread speed"); - print_res(tname, td->system_time_ns / 1e9, + print_res(tname, td->system_time_ns / NSEC_PER_SEC, "secs", "thread-system-time", "system CPU time/thread"); - print_res(tname, td->user_time_ns / 1e9, + print_res(tname, td->user_time_ns / NSEC_PER_SEC, "secs", "thread-user-time", "user CPU time/thread"); } } diff --git a/tools/perf/bench/sched-messaging.c b/tools/perf/bench/sched-messaging.c index bfaf9503de8e..6a111e775210 100644 --- a/tools/perf/bench/sched-messaging.c +++ b/tools/perf/bench/sched-messaging.c @@ -29,6 +29,7 @@ #include <poll.h> #include <limits.h> #include <err.h> +#include <linux/time64.h> #define DATASIZE 100 @@ -312,11 +313,11 @@ int bench_sched_messaging(int argc, const char **argv, thread_mode ? "threads" : "processes"); printf(" %14s: %lu.%03lu [sec]\n", "Total time", diff.tv_sec, - (unsigned long) (diff.tv_usec/1000)); + (unsigned long) (diff.tv_usec / USEC_PER_MSEC)); break; case BENCH_FORMAT_SIMPLE: printf("%lu.%03lu\n", diff.tv_sec, - (unsigned long) (diff.tv_usec/1000)); + (unsigned long) (diff.tv_usec / USEC_PER_MSEC)); break; default: /* reaching here is something disaster */ diff --git a/tools/perf/bench/sched-pipe.c b/tools/perf/bench/sched-pipe.c index 1dc2d13cc272..2243f0150d76 100644 --- a/tools/perf/bench/sched-pipe.c +++ b/tools/perf/bench/sched-pipe.c @@ -25,6 +25,7 @@ #include <sys/time.h> #include <sys/types.h> #include <sys/syscall.h> +#include <linux/time64.h> #include <pthread.h> @@ -153,24 +154,24 @@ int bench_sched_pipe(int argc, const char **argv, const char *prefix __maybe_unu printf("# Executed %d pipe operations between two %s\n\n", loops, threaded ? "threads" : "processes"); - result_usec = diff.tv_sec * 1000000; + result_usec = diff.tv_sec * USEC_PER_SEC; result_usec += diff.tv_usec; printf(" %14s: %lu.%03lu [sec]\n\n", "Total time", diff.tv_sec, - (unsigned long) (diff.tv_usec/1000)); + (unsigned long) (diff.tv_usec / USEC_PER_MSEC)); printf(" %14lf usecs/op\n", (double)result_usec / (double)loops); printf(" %14d ops/sec\n", (int)((double)loops / - ((double)result_usec / (double)1000000))); + ((double)result_usec / (double)USEC_PER_SEC))); break; case BENCH_FORMAT_SIMPLE: printf("%lu.%03lu\n", diff.tv_sec, - (unsigned long) (diff.tv_usec / 1000)); + (unsigned long) (diff.tv_usec / USEC_PER_MSEC)); break; default: diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 9c1034d81b4f..ebb628332a6e 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -30,6 +30,7 @@ #include "util/tool.h" #include "util/data.h" #include "arch/common.h" +#include "util/block-range.h" #include <dlfcn.h> #include <linux/bitmap.h> @@ -46,6 +47,103 @@ struct perf_annotate { DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); }; +/* + * Given one basic block: + * + * from to branch_i + * * ----> * + * | + * | block + * v + * * ----> * + * from to branch_i+1 + * + * where the horizontal are the branches and the vertical is the executed + * block of instructions. + * + * We count, for each 'instruction', the number of blocks that covered it as + * well as count the ratio each branch is taken. + * + * We can do this without knowing the actual instruction stream by keeping + * track of the address ranges. We break down ranges such that there is no + * overlap and iterate from the start until the end. + * + * @acme: once we parse the objdump output _before_ processing the samples, + * we can easily fold the branch.cycles IPC bits in. + */ +static void process_basic_block(struct addr_map_symbol *start, + struct addr_map_symbol *end, + struct branch_flags *flags) +{ + struct symbol *sym = start->sym; + struct annotation *notes = sym ? symbol__annotation(sym) : NULL; + struct block_range_iter iter; + struct block_range *entry; + + /* + * Sanity; NULL isn't executable and the CPU cannot execute backwards + */ + if (!start->addr || start->addr > end->addr) + return; + + iter = block_range__create(start->addr, end->addr); + if (!block_range_iter__valid(&iter)) + return; + + /* + * First block in range is a branch target. + */ + entry = block_range_iter(&iter); + assert(entry->is_target); + entry->entry++; + + do { + entry = block_range_iter(&iter); + + entry->coverage++; + entry->sym = sym; + + if (notes) + notes->max_coverage = max(notes->max_coverage, entry->coverage); + + } while (block_range_iter__next(&iter)); + + /* + * Last block in rage is a branch. + */ + entry = block_range_iter(&iter); + assert(entry->is_branch); + entry->taken++; + if (flags->predicted) + entry->pred++; +} + +static void process_branch_stack(struct branch_stack *bs, struct addr_location *al, + struct perf_sample *sample) +{ + struct addr_map_symbol *prev = NULL; + struct branch_info *bi; + int i; + + if (!bs || !bs->nr) + return; + + bi = sample__resolve_bstack(sample, al); + if (!bi) + return; + + for (i = bs->nr - 1; i >= 0; i--) { + /* + * XXX filter against symbol + */ + if (prev) + process_basic_block(prev, &bi[i].from, &bi[i].flags); + prev = &bi[i].to; + } + + free(bi); +} + static int perf_evsel__add_sample(struct perf_evsel *evsel, struct perf_sample *sample, struct addr_location *al, @@ -72,6 +170,12 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, return 0; } + /* + * XXX filtered samples can still have branch entires pointing into our + * symbol and are missed. + */ + process_branch_stack(sample->branch_stack, al, sample); + sample->period = 1; sample->weight = 1; @@ -204,8 +308,6 @@ static int __cmd_annotate(struct perf_annotate *ann) struct perf_evsel *pos; u64 total_nr_samples; - machines__set_symbol_filter(&session->machines, symbol__annotate_init); - if (ann->cpu_list) { ret = perf_session__cpu_bitmap(session, ann->cpu_list, ann->cpu_bitmap); @@ -367,7 +469,10 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) if (annotate.session == NULL) return -1; - symbol_conf.priv_size = sizeof(struct annotation); + ret = symbol__annotation_init(); + if (ret < 0) + goto out_delete; + symbol_conf.try_vmlinux_path = true; ret = symbol__init(&annotate.session->header.env); diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 21ee753211ad..9ff0db4e2d0c 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -1033,7 +1033,9 @@ static int hpp__entry_global(struct perf_hpp_fmt *_fmt, struct perf_hpp *hpp, } static int hpp__header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, - struct hists *hists __maybe_unused) + struct hists *hists __maybe_unused, + int line __maybe_unused, + int *span __maybe_unused) { struct diff_hpp_fmt *dfmt = container_of(fmt, struct diff_hpp_fmt, fmt); diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 73c1c4cc3600..b9bc7e39833a 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -429,7 +429,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool, if (al.map != NULL) { if (!al.map->dso->hit) { al.map->dso->hit = 1; - if (map__load(al.map, NULL) >= 0) { + if (map__load(al.map) >= 0) { dso__inject_build_id(al.map->dso, tool, machine); /* * If this fails, too bad, let the other side diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index fdde1bd3e306..d426dcb18ce9 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -330,7 +330,7 @@ static int build_alloc_func_list(void) } kernel_map = machine__kernel_map(machine); - if (map__load(kernel_map, NULL) < 0) { + if (map__load(kernel_map) < 0) { pr_err("cannot load kernel map\n"); return -ENOENT; } @@ -979,7 +979,7 @@ static void __print_slab_result(struct rb_root *root, if (is_caller) { addr = data->call_site; if (!raw_ip) - sym = machine__find_kernel_function(machine, addr, &map, NULL); + sym = machine__find_kernel_function(machine, addr, &map); } else addr = data->ptr; @@ -1043,8 +1043,7 @@ static void __print_page_alloc_result(struct perf_session *session, int n_lines) char *caller = buf; data = rb_entry(next, struct page_stat, node); - sym = machine__find_kernel_function(machine, data->callsite, - &map, NULL); + sym = machine__find_kernel_function(machine, data->callsite, &map); if (sym && sym->name) caller = sym->name; else @@ -1086,8 +1085,7 @@ static void __print_page_caller_result(struct perf_session *session, int n_lines char *caller = buf; data = rb_entry(next, struct page_stat, node); - sym = machine__find_kernel_function(machine, data->callsite, - &map, NULL); + sym = machine__find_kernel_function(machine, data->callsite, &map); if (sym && sym->name) caller = sym->name; else diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 5e2127e04f83..08fa88f62a24 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -24,6 +24,7 @@ #include <sys/timerfd.h> #endif +#include <linux/time64.h> #include <termios.h> #include <semaphore.h> #include <pthread.h> @@ -362,7 +363,7 @@ static bool handle_end_event(struct perf_kvm_stat *kvm, if (!skip_event(decode)) { pr_info("%" PRIu64 " VM %d, vcpu %d: %s event took %" PRIu64 "usec\n", sample->time, sample->pid, vcpu_record->vcpu_id, - decode, time_diff/1000); + decode, time_diff / NSEC_PER_USEC); } } @@ -608,15 +609,15 @@ static void print_result(struct perf_kvm_stat *kvm) pr_info("%10llu ", (unsigned long long)ecount); pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100); pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100); - pr_info("%9.2fus ", (double)min / 1e3); - pr_info("%9.2fus ", (double)max / 1e3); - pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount/1e3, + pr_info("%9.2fus ", (double)min / NSEC_PER_USEC); + pr_info("%9.2fus ", (double)max / NSEC_PER_USEC); + pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount / NSEC_PER_USEC, kvm_event_rel_stddev(vcpu, event)); pr_info("\n"); } pr_info("\nTotal Samples:%" PRIu64 ", Total events handled time:%.2fus.\n\n", - kvm->total_count, kvm->total_time / 1e3); + kvm->total_count, kvm->total_time / (double)NSEC_PER_USEC); if (kvm->lost_events) pr_info("\nLost events: %" PRIu64 "\n\n", kvm->lost_events); diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index ee5b42173ba3..f87996b0cb29 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -326,6 +326,11 @@ static int perf_add_probe_events(struct perf_probe_event *pevs, int npevs) if (ret < 0) goto out_cleanup; + if (params.command == 'D') { /* it shows definition */ + ret = show_probe_trace_events(pevs, npevs); + goto out_cleanup; + } + ret = apply_perf_probe_events(pevs, npevs); if (ret < 0) goto out_cleanup; @@ -454,6 +459,14 @@ out: return ret; } +#ifdef HAVE_DWARF_SUPPORT +#define PROBEDEF_STR \ + "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT [[NAME=]ARG ...]" +#else +#define PROBEDEF_STR "[EVENT=]FUNC[+OFF|%return] [[NAME=]ARG ...]" +#endif + + static int __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) { @@ -479,13 +492,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) opt_set_filter_with_command, DEFAULT_LIST_FILTER), OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.", opt_set_filter_with_command), - OPT_CALLBACK('a', "add", NULL, -#ifdef HAVE_DWARF_SUPPORT - "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT" - " [[NAME=]ARG ...]", -#else - "[EVENT=]FUNC[+OFF|%return] [[NAME=]ARG ...]", -#endif + OPT_CALLBACK('a', "add", NULL, PROBEDEF_STR, "probe point definition, where\n" "\t\tGROUP:\tGroup name (optional)\n" "\t\tEVENT:\tEvent name\n" @@ -503,6 +510,9 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) "\t\tARG:\tProbe argument (kprobe-tracer argument format.)\n", #endif opt_add_probe_event), + OPT_CALLBACK('D', "definition", NULL, PROBEDEF_STR, + "Show trace event definition of given traceevent for k/uprobe_events.", + opt_add_probe_event), OPT_BOOLEAN('f', "force", &probe_conf.force_add, "forcibly add events" " with existing name"), OPT_CALLBACK('L', "line", NULL, @@ -548,6 +558,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) set_option_flag(options, 'a', "add", PARSE_OPT_EXCLUSIVE); set_option_flag(options, 'd', "del", PARSE_OPT_EXCLUSIVE); + set_option_flag(options, 'D', "definition", PARSE_OPT_EXCLUSIVE); set_option_flag(options, 'l', "list", PARSE_OPT_EXCLUSIVE); #ifdef HAVE_DWARF_SUPPORT set_option_flag(options, 'L', "line", PARSE_OPT_EXCLUSIVE); @@ -600,6 +611,14 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) */ symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); + /* + * Except for --list, --del and --add, other command doesn't depend + * nor change running kernel. So if user gives offline vmlinux, + * ignore its buildid. + */ + if (!strchr("lda", params.command) && symbol_conf.vmlinux_name) + symbol_conf.ignore_vmlinux_buildid = true; + switch (params.command) { case 'l': if (params.uprobes) { @@ -643,7 +662,9 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) return ret; } break; + case 'D': case 'a': + /* Ensure the last given target is used */ if (params.target && !params.target_used) { pr_err(" Error: -x/-m must follow the probe definitions.\n"); diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 6355902fbfc8..03251c7f14ec 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -42,7 +42,7 @@ #include <sched.h> #include <sys/mman.h> #include <asm/bug.h> - +#include <linux/time64.h> struct record { struct perf_tool tool; @@ -96,7 +96,7 @@ backward_rb_find_range(void *buf, int mask, u64 head, u64 *start, u64 *end) *start = head; while (true) { if (evt_head - head >= (unsigned int)size) { - pr_debug("Finshed reading backward ring buffer: rewind\n"); + pr_debug("Finished reading backward ring buffer: rewind\n"); if (evt_head - head > (unsigned int)size) evt_head -= pheader->size; *end = evt_head; @@ -106,7 +106,7 @@ backward_rb_find_range(void *buf, int mask, u64 head, u64 *start, u64 *end) pheader = (struct perf_event_header *)(buf + (evt_head & mask)); if (pheader->size == 0) { - pr_debug("Finshed reading backward ring buffer: get start\n"); + pr_debug("Finished reading backward ring buffer: get start\n"); *end = evt_head; return 0; } @@ -954,7 +954,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) } if (opts->initial_delay) { - usleep(opts->initial_delay * 1000); + usleep(opts->initial_delay * USEC_PER_MSEC); perf_evlist__enable(rec->evlist); } diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 949e5a15c960..6e88460cd13d 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -89,6 +89,10 @@ static int report__config(const char *var, const char *value, void *cb) rep->queue_size = perf_config_u64(var, value); return 0; } + if (!strcmp(var, "report.sort_order")) { + default_sort_order = strdup(value); + return 0; + } return 0; } @@ -931,7 +935,6 @@ repeat: if (symbol_conf.report_hierarchy) { /* disable incompatible options */ - symbol_conf.event_group = false; symbol_conf.cumulate_callchain = false; if (field_order) { @@ -980,9 +983,9 @@ repeat: * implementation. */ if (ui__has_annotation()) { - symbol_conf.priv_size = sizeof(struct annotation); - machines__set_symbol_filter(&session->machines, - symbol__annotate_init); + ret = symbol__annotation_init(); + if (ret < 0) + goto error; /* * For searching by name on the "Browse map details". * providing it only in verbose mode not to bloat too diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 0dfe8df2ab9b..f5503ca22e1c 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -26,6 +26,7 @@ #include <pthread.h> #include <math.h> #include <api/fs/fs.h> +#include <linux/time64.h> #define PR_SET_NAME 15 /* Set process name */ #define MAX_CPUS 4096 @@ -199,7 +200,7 @@ static u64 get_nsecs(void) clock_gettime(CLOCK_MONOTONIC, &ts); - return ts.tv_sec * 1000000000ULL + ts.tv_nsec; + return ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec; } static void burn_nsecs(struct perf_sched *sched, u64 nsecs) @@ -223,7 +224,7 @@ static void sleep_nsecs(u64 nsecs) static void calibrate_run_measurement_overhead(struct perf_sched *sched) { - u64 T0, T1, delta, min_delta = 1000000000ULL; + u64 T0, T1, delta, min_delta = NSEC_PER_SEC; int i; for (i = 0; i < 10; i++) { @@ -240,7 +241,7 @@ static void calibrate_run_measurement_overhead(struct perf_sched *sched) static void calibrate_sleep_measurement_overhead(struct perf_sched *sched) { - u64 T0, T1, delta, min_delta = 1000000000ULL; + u64 T0, T1, delta, min_delta = NSEC_PER_SEC; int i; for (i = 0; i < 10; i++) { @@ -452,8 +453,8 @@ static u64 get_cpu_usage_nsec_parent(void) err = getrusage(RUSAGE_SELF, &ru); BUG_ON(err); - sum = ru.ru_utime.tv_sec*1e9 + ru.ru_utime.tv_usec*1e3; - sum += ru.ru_stime.tv_sec*1e9 + ru.ru_stime.tv_usec*1e3; + sum = ru.ru_utime.tv_sec * NSEC_PER_SEC + ru.ru_utime.tv_usec * NSEC_PER_USEC; + sum += ru.ru_stime.tv_sec * NSEC_PER_SEC + ru.ru_stime.tv_usec * NSEC_PER_USEC; return sum; } @@ -667,12 +668,12 @@ static void run_one_test(struct perf_sched *sched) sched->run_avg = delta; sched->run_avg = (sched->run_avg * (sched->replay_repeat - 1) + delta) / sched->replay_repeat; - printf("#%-3ld: %0.3f, ", sched->nr_runs, (double)delta / 1000000.0); + printf("#%-3ld: %0.3f, ", sched->nr_runs, (double)delta / NSEC_PER_MSEC); - printf("ravg: %0.2f, ", (double)sched->run_avg / 1e6); + printf("ravg: %0.2f, ", (double)sched->run_avg / NSEC_PER_MSEC); printf("cpu: %0.2f / %0.2f", - (double)sched->cpu_usage / 1e6, (double)sched->runavg_cpu_usage / 1e6); + (double)sched->cpu_usage / NSEC_PER_MSEC, (double)sched->runavg_cpu_usage / NSEC_PER_MSEC); #if 0 /* @@ -680,8 +681,8 @@ static void run_one_test(struct perf_sched *sched) * accurate than the sched->sum_exec_runtime based statistics: */ printf(" [%0.2f / %0.2f]", - (double)sched->parent_cpu_usage/1e6, - (double)sched->runavg_parent_cpu_usage/1e6); + (double)sched->parent_cpu_usage / NSEC_PER_MSEC, + (double)sched->runavg_parent_cpu_usage / NSEC_PER_MSEC); #endif printf("\n"); @@ -696,13 +697,13 @@ static void test_calibrations(struct perf_sched *sched) u64 T0, T1; T0 = get_nsecs(); - burn_nsecs(sched, 1e6); + burn_nsecs(sched, NSEC_PER_MSEC); T1 = get_nsecs(); printf("the run test took %" PRIu64 " nsecs\n", T1 - T0); T0 = get_nsecs(); - sleep_nsecs(1e6); + sleep_nsecs(NSEC_PER_MSEC); T1 = get_nsecs(); printf("the sleep test took %" PRIu64 " nsecs\n", T1 - T0); @@ -1213,10 +1214,10 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_ avg = work_list->total_lat / work_list->nb_atoms; printf("|%11.3f ms |%9" PRIu64 " | avg:%9.3f ms | max:%9.3f ms | max at: %13.6f s\n", - (double)work_list->total_runtime / 1e6, - work_list->nb_atoms, (double)avg / 1e6, - (double)work_list->max_lat / 1e6, - (double)work_list->max_lat_at / 1e9); + (double)work_list->total_runtime / NSEC_PER_MSEC, + work_list->nb_atoms, (double)avg / NSEC_PER_MSEC, + (double)work_list->max_lat / NSEC_PER_MSEC, + (double)work_list->max_lat_at / NSEC_PER_SEC); } static int pid_cmp(struct work_atoms *l, struct work_atoms *r) @@ -1491,7 +1492,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, if (sched->map.cpus && !cpu_map__has(sched->map.cpus, this_cpu)) goto out; - color_fprintf(stdout, color, " %12.6f secs ", (double)timestamp/1e9); + color_fprintf(stdout, color, " %12.6f secs ", (double)timestamp / NSEC_PER_SEC); if (new_shortname) { const char *pid_color = color; @@ -1753,7 +1754,7 @@ static int perf_sched__lat(struct perf_sched *sched) printf(" -----------------------------------------------------------------------------------------------------------------\n"); printf(" TOTAL: |%11.3f ms |%9" PRIu64 " |\n", - (double)sched->all_runtime / 1e6, sched->all_count); + (double)sched->all_runtime / NSEC_PER_MSEC, sched->all_count); printf(" ---------------------------------------------------\n"); diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index c859e59dfe3e..7228d141a789 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -24,6 +24,7 @@ #include "util/thread-stack.h" #include <linux/bitmap.h> #include <linux/stringify.h> +#include <linux/time64.h> #include "asm/bug.h" #include "util/mem-events.h" @@ -464,9 +465,9 @@ static void print_sample_start(struct perf_sample *sample, if (PRINT_FIELD(TIME)) { nsecs = sample->time; - secs = nsecs / NSECS_PER_SEC; - nsecs -= secs * NSECS_PER_SEC; - usecs = nsecs / NSECS_PER_USEC; + secs = nsecs / NSEC_PER_SEC; + nsecs -= secs * NSEC_PER_SEC; + usecs = nsecs / NSEC_PER_USEC; if (nanosecs) printf("%5lu.%09llu: ", secs, nsecs); else @@ -521,11 +522,11 @@ static void print_sample_brstacksym(struct perf_sample *sample, thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, from, &alf); if (alf.map) - alf.sym = map__find_symbol(alf.map, alf.addr, NULL); + alf.sym = map__find_symbol(alf.map, alf.addr); thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, to, &alt); if (alt.map) - alt.sym = map__find_symbol(alt.map, alt.addr, NULL); + alt.sym = map__find_symbol(alt.map, alt.addr); symbol__fprintf_symname_offs(alf.sym, &alf, stdout); putchar('/'); diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 3c7452b39f57..90882b1d6a91 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -65,6 +65,7 @@ #include "util/group.h" #include "asm/bug.h" +#include <linux/time64.h> #include <api/fs/fs.h> #include <stdlib.h> #include <sys/prctl.h> @@ -172,7 +173,7 @@ static inline void diff_timespec(struct timespec *r, struct timespec *a, { r->tv_sec = a->tv_sec - b->tv_sec; if (a->tv_nsec < b->tv_nsec) { - r->tv_nsec = a->tv_nsec + 1000000000L - b->tv_nsec; + r->tv_nsec = a->tv_nsec + NSEC_PER_SEC - b->tv_nsec; r->tv_sec--; } else { r->tv_nsec = a->tv_nsec - b->tv_nsec ; @@ -354,7 +355,7 @@ static void process_interval(void) diff_timespec(&rs, &ts, &ref_time); if (STAT_RECORD) { - if (WRITE_STAT_ROUND_EVENT(rs.tv_sec * NSECS_PER_SEC + rs.tv_nsec, INTERVAL)) + if (WRITE_STAT_ROUND_EVENT(rs.tv_sec * NSEC_PER_SEC + rs.tv_nsec, INTERVAL)) pr_err("failed to write stat round event\n"); } @@ -364,7 +365,7 @@ static void process_interval(void) static void enable_counters(void) { if (initial_delay) - usleep(initial_delay * 1000); + usleep(initial_delay * USEC_PER_MSEC); /* * We need to enable counters only if: @@ -541,8 +542,8 @@ static int __run_perf_stat(int argc, const char **argv) bool is_pipe = STAT_RECORD ? perf_stat.file.is_pipe : false; if (interval) { - ts.tv_sec = interval / 1000; - ts.tv_nsec = (interval % 1000) * 1000000; + ts.tv_sec = interval / USEC_PER_MSEC; + ts.tv_nsec = (interval % USEC_PER_MSEC) * NSEC_PER_MSEC; } else { ts.tv_sec = 1; ts.tv_nsec = 0; @@ -971,7 +972,7 @@ static void print_metric_header(void *ctx, const char *color __maybe_unused, static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg) { FILE *output = stat_config.output; - double msecs = avg / 1e6; + double msecs = avg / NSEC_PER_MSEC; const char *fmt_v, *fmt_n; char name[25]; @@ -1460,7 +1461,7 @@ static void print_footer(void) if (!null_run) fprintf(output, "\n"); fprintf(output, " %17.9f seconds time elapsed", - avg_stats(&walltime_nsecs_stats)/1e9); + avg_stats(&walltime_nsecs_stats) / NSEC_PER_SEC); if (run_count > 1) { fprintf(output, " "); print_noise_pct(stddev_stats(&walltime_nsecs_stats), @@ -2175,8 +2176,8 @@ static int process_stat_round_event(struct perf_tool *tool __maybe_unused, update_stats(&walltime_nsecs_stats, stat_round->time); if (stat_config.interval && stat_round->time) { - tsh.tv_sec = stat_round->time / NSECS_PER_SEC; - tsh.tv_nsec = stat_round->time % NSECS_PER_SEC; + tsh.tv_sec = stat_round->time / NSEC_PER_SEC; + tsh.tv_nsec = stat_round->time % NSEC_PER_SEC; ts = &tsh; } diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 733a55422d03..e7eaa298d34a 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -24,6 +24,7 @@ #include "util/evlist.h" #include "util/evsel.h" #include <linux/rbtree.h> +#include <linux/time64.h> #include "util/symbol.h" #include "util/callchain.h" #include "util/strlist.h" @@ -1288,9 +1289,9 @@ static void draw_process_bars(struct timechart *tchart) if (c->comm) { char comm[256]; if (c->total_time > 5000000000) /* 5 seconds */ - sprintf(comm, "%s:%i (%2.2fs)", c->comm, p->pid, c->total_time / 1000000000.0); + sprintf(comm, "%s:%i (%2.2fs)", c->comm, p->pid, c->total_time / (double)NSEC_PER_SEC); else - sprintf(comm, "%s:%i (%3.1fms)", c->comm, p->pid, c->total_time / 1000000.0); + sprintf(comm, "%s:%i (%3.1fms)", c->comm, p->pid, c->total_time / (double)NSEC_PER_MSEC); svg_text(Y, c->start_time, comm); } @@ -1637,7 +1638,7 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name) write_svg_file(tchart, output_name); pr_info("Written %2.1f seconds of trace to %s.\n", - (tchart->last_time - tchart->first_time) / 1000000000.0, output_name); + (tchart->last_time - tchart->first_time) / (double)NSEC_PER_SEC, output_name); out_delete: perf_session__delete(session); return ret; @@ -1901,10 +1902,10 @@ parse_time(const struct option *opt, const char *arg, int __maybe_unused unset) if (sscanf(arg, "%" PRIu64 "%cs", value, &unit) > 0) { switch (unit) { case 'm': - *value *= 1000000; + *value *= NSEC_PER_MSEC; break; case 'u': - *value *= 1000; + *value *= NSEC_PER_USEC; break; case 'n': break; @@ -1928,7 +1929,7 @@ int cmd_timechart(int argc, const char **argv, .ordered_events = true, }, .proc_num = 15, - .min_time = 1000000, + .min_time = NSEC_PER_MSEC, .merge_dist = 1000, }; const char *output_name = "output.svg"; diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 418ed94756d3..400785702566 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -68,6 +68,7 @@ #include <sys/mman.h> #include <linux/stringify.h> +#include <linux/time64.h> #include <linux/types.h> static volatile int done; @@ -624,7 +625,7 @@ static void *display_thread(void *arg) display_setup_sig(); pthread__unblock_sigwinch(); repeat: - delay_msecs = top->delay_secs * 1000; + delay_msecs = top->delay_secs * MSEC_PER_SEC; set_term_quiet_input(&save); /* trash return*/ getc(stdin); @@ -656,34 +657,6 @@ repeat: return NULL; } -static int symbol_filter(struct map *map, struct symbol *sym) -{ - const char *name = sym->name; - - if (!__map__is_kernel(map)) - return 0; - /* - * ppc64 uses function descriptors and appends a '.' to the - * start of every instruction address. Remove it. - */ - if (name[0] == '.') - name++; - - if (!strcmp(name, "_text") || - !strcmp(name, "_etext") || - !strcmp(name, "_sinittext") || - !strncmp("init_module", name, 11) || - !strncmp("cleanup_module", name, 14) || - strstr(name, "_text_start") || - strstr(name, "_text_end")) - return 1; - - if (symbol__is_idle(sym)) - sym->ignore = true; - - return 0; -} - static int hist_iter__top_callback(struct hist_entry_iter *iter, struct addr_location *al, bool single, void *arg) @@ -782,7 +755,7 @@ static void perf_event__process_sample(struct perf_tool *tool, } } - if (al.sym == NULL || !al.sym->ignore) { + if (al.sym == NULL || !al.sym->idle) { struct hists *hists = evsel__hists(evsel); struct hist_entry_iter iter = { .evsel = evsel, @@ -948,8 +921,6 @@ static int __cmd_top(struct perf_top *top) if (top->session == NULL) return -1; - machines__set_symbol_filter(&top->session->machines, symbol_filter); - if (!objdump_path) { ret = perf_env__lookup_objdump(&top->session->header.env); if (ret) @@ -1323,7 +1294,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) if (symbol_conf.cumulate_callchain && !callchain_param.order_set) callchain_param.order = ORDER_CALLER; - symbol_conf.priv_size = sizeof(struct annotation); + status = symbol__annotation_init(); + if (status < 0) + goto out_delete_evlist; symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); if (symbol__init(NULL) < 0) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index b8c6766301db..b4fc1ab3d2a7 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -45,6 +45,7 @@ #include <linux/audit.h> #include <linux/random.h> #include <linux/stringify.h> +#include <linux/time64.h> #ifndef O_CLOEXEC # define O_CLOEXEC 02000000 diff --git a/tools/perf/perf-sys.h b/tools/perf/perf-sys.h index 7ed72a475c57..e4b717e9eb6c 100644 --- a/tools/perf/perf-sys.h +++ b/tools/perf/perf-sys.h @@ -20,7 +20,6 @@ #endif #ifdef __powerpc__ -#include "../../arch/powerpc/include/uapi/asm/unistd.h" #define CPUINFO_PROC {"cpu"} #endif diff --git a/tools/perf/perf.h b/tools/perf/perf.h index cb0f1356ff81..9a0236a4cf95 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -14,13 +14,6 @@ void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu, #define HAVE_ATTR_TEST #include "perf-sys.h" -#ifndef NSEC_PER_SEC -# define NSEC_PER_SEC 1000000000ULL -#endif -#ifndef NSEC_PER_USEC -# define NSEC_PER_USEC 1000ULL -#endif - static inline unsigned long long rdclock(void) { struct timespec ts; diff --git a/tools/perf/tests/backward-ring-buffer.c b/tools/perf/tests/backward-ring-buffer.c index 615780cbfe1d..e6d1816e431a 100644 --- a/tools/perf/tests/backward-ring-buffer.c +++ b/tools/perf/tests/backward-ring-buffer.c @@ -97,7 +97,7 @@ int test__backward_ring_buffer(int subtest __maybe_unused) evlist = perf_evlist__new(); if (!evlist) { - pr_debug("No ehough memory to create evlist\n"); + pr_debug("No enough memory to create evlist\n"); return TEST_FAIL; } diff --git a/tools/perf/tests/bpf.c b/tools/perf/tests/bpf.c index fc54064b9186..2673e86ed50f 100644 --- a/tools/perf/tests/bpf.c +++ b/tools/perf/tests/bpf.c @@ -125,7 +125,7 @@ static int do_test(struct bpf_object *obj, int (*func)(void), /* Instead of perf_evlist__new_default, don't add default events */ evlist = perf_evlist__new(); if (!evlist) { - pr_debug("No ehough memory to create evlist\n"); + pr_debug("No enough memory to create evlist\n"); return TEST_FAIL; } diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index 2af156a8d4e5..ff5bc6363a79 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c @@ -263,7 +263,7 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, * Converting addresses for use by objdump requires more information. * map__load() does that. See map__rip_2objdump() for details. */ - if (map__load(al.map, NULL)) + if (map__load(al.map)) return -1; /* objdump struggles with kcore - try each map only once */ @@ -511,7 +511,7 @@ static int do_test_code_reading(bool try_kcore) /* Load kernel map */ map = machine__kernel_map(machine); - ret = map__load(map, NULL); + ret = map__load(map); if (ret < 0) { pr_debug("map__load failed\n"); goto out_err; diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c index e63abab7d5a1..a5082331f246 100644 --- a/tools/perf/tests/vmlinux-kallsyms.c +++ b/tools/perf/tests/vmlinux-kallsyms.c @@ -8,14 +8,6 @@ #include "debug.h" #include "machine.h" -static int vmlinux_matches_kallsyms_filter(struct map *map __maybe_unused, - struct symbol *sym) -{ - bool *visited = symbol__priv(sym); - *visited = true; - return 0; -} - #define UM(x) kallsyms_map->unmap_ip(kallsyms_map, (x)) int test__vmlinux_matches_kallsyms(int subtest __maybe_unused) @@ -28,6 +20,7 @@ int test__vmlinux_matches_kallsyms(int subtest __maybe_unused) enum map_type type = MAP__FUNCTION; struct maps *maps = &vmlinux.kmaps.maps[type]; u64 mem_start, mem_end; + bool header_printed; /* * Step 1: @@ -61,7 +54,7 @@ int test__vmlinux_matches_kallsyms(int subtest __maybe_unused) * be compacted against the list of modules found in the "vmlinux" * code and with the one got from /proc/modules from the "kallsyms" code. */ - if (__machine__load_kallsyms(&kallsyms, "/proc/kallsyms", type, true, NULL) <= 0) { + if (__machine__load_kallsyms(&kallsyms, "/proc/kallsyms", type, true) <= 0) { pr_debug("dso__load_kallsyms "); goto out; } @@ -99,8 +92,7 @@ int test__vmlinux_matches_kallsyms(int subtest __maybe_unused) * maps__reloc_vmlinux will notice and set proper ->[un]map_ip routines * to fixup the symbols. */ - if (machine__load_vmlinux_path(&vmlinux, type, - vmlinux_matches_kallsyms_filter) <= 0) { + if (machine__load_vmlinux_path(&vmlinux, type) <= 0) { pr_debug("Couldn't find a vmlinux that matches the kernel running on this machine, skipping test\n"); err = TEST_SKIP; goto out; @@ -126,7 +118,7 @@ int test__vmlinux_matches_kallsyms(int subtest __maybe_unused) mem_end = vmlinux_map->unmap_ip(vmlinux_map, sym->end); first_pair = machine__find_kernel_symbol(&kallsyms, type, - mem_start, NULL, NULL); + mem_start, NULL); pair = first_pair; if (pair && UM(pair->start) == mem_start) { @@ -143,7 +135,7 @@ next_pair: */ s64 skew = mem_end - UM(pair->end); if (llabs(skew) >= page_size) - pr_debug("%#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n", + pr_debug("WARN: %#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n", mem_start, sym->name, mem_end, UM(pair->end)); @@ -154,22 +146,23 @@ next_pair: * kallsyms. */ continue; - } else { - pair = machine__find_kernel_symbol_by_name(&kallsyms, type, sym->name, NULL, NULL); + pair = machine__find_kernel_symbol_by_name(&kallsyms, type, sym->name, NULL); if (pair) { if (UM(pair->start) == mem_start) goto next_pair; - pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n", + pr_debug("WARN: %#" PRIx64 ": diff name v: %s k: %s\n", mem_start, sym->name, pair->name); } else { - pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n", + pr_debug("WARN: %#" PRIx64 ": diff name v: %s k: %s\n", mem_start, sym->name, first_pair->name); } + + continue; } } else - pr_debug("%#" PRIx64 ": %s not on kallsyms\n", + pr_debug("ERR : %#" PRIx64 ": %s not on kallsyms\n", mem_start, sym->name); err = -1; @@ -178,7 +171,7 @@ next_pair: if (!verbose) goto out; - pr_info("Maps only in vmlinux:\n"); + header_printed = false; for (map = maps__first(maps); map; map = map__next(map)) { struct map * @@ -192,13 +185,18 @@ next_pair: (map->dso->kernel ? map->dso->short_name : map->dso->name)); - if (pair) + if (pair) { pair->priv = 1; - else + } else { + if (!header_printed) { + pr_info("WARN: Maps only in vmlinux:\n"); + header_printed = true; + } map__fprintf(map, stderr); + } } - pr_info("Maps in vmlinux with a different name in kallsyms:\n"); + header_printed = false; for (map = maps__first(maps); map; map = map__next(map)) { struct map *pair; @@ -211,24 +209,33 @@ next_pair: continue; if (pair->start == mem_start) { - pair->priv = 1; - pr_info(" %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as", + if (!header_printed) { + pr_info("WARN: Maps in vmlinux with a different name in kallsyms:\n"); + header_printed = true; + } + + pr_info("WARN: %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as", map->start, map->end, map->pgoff, map->dso->name); if (mem_end != pair->end) - pr_info(":\n*%" PRIx64 "-%" PRIx64 " %" PRIx64, + pr_info(":\nWARN: *%" PRIx64 "-%" PRIx64 " %" PRIx64, pair->start, pair->end, pair->pgoff); pr_info(" %s\n", pair->dso->name); pair->priv = 1; } } - pr_info("Maps only in kallsyms:\n"); + header_printed = false; maps = &kallsyms.kmaps.maps[type]; for (map = maps__first(maps); map; map = map__next(map)) { - if (!map->priv) + if (!map->priv) { + if (!header_printed) { + pr_info("WARN: Maps only in kallsyms:\n"); + header_printed = true; + } map__fprintf(map, stderr); + } } out: machine__exit(&kallsyms); diff --git a/tools/perf/trace/beauty/mmap.c b/tools/perf/trace/beauty/mmap.c index d0a3a8e402e7..fd710ab33684 100644 --- a/tools/perf/trace/beauty/mmap.c +++ b/tools/perf/trace/beauty/mmap.c @@ -1,8 +1,4 @@ -#include <sys/mman.h> - -#ifndef PROT_SEM -#define PROT_SEM 0x8 -#endif +#include <uapi/linux/mman.h> static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size, struct syscall_arg *arg) @@ -33,31 +29,6 @@ static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size, #define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot -#ifndef MAP_FIXED -#define MAP_FIXED 0x10 -#endif - -#ifndef MAP_ANONYMOUS -#define MAP_ANONYMOUS 0x20 -#endif - -#ifndef MAP_32BIT -#define MAP_32BIT 0x40 -#endif - -#ifndef MAP_STACK -#define MAP_STACK 0x20000 -#endif - -#ifndef MAP_HUGETLB -#define MAP_HUGETLB 0x40000 -#endif - -#ifndef MAP_UNINITIALIZED -#define MAP_UNINITIALIZED 0x4000000 -#endif - - static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size, struct syscall_arg *arg) { @@ -95,13 +66,6 @@ static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size, #define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags -#ifndef MREMAP_MAYMOVE -#define MREMAP_MAYMOVE 1 -#endif -#ifndef MREMAP_FIXED -#define MREMAP_FIXED 2 -#endif - static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size, struct syscall_arg *arg) { @@ -125,39 +89,6 @@ static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size, #define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags -#ifndef MADV_HWPOISON -#define MADV_HWPOISON 100 -#endif - -#ifndef MADV_SOFT_OFFLINE -#define MADV_SOFT_OFFLINE 101 -#endif - -#ifndef MADV_MERGEABLE -#define MADV_MERGEABLE 12 -#endif - -#ifndef MADV_UNMERGEABLE -#define MADV_UNMERGEABLE 13 -#endif - -#ifndef MADV_HUGEPAGE -#define MADV_HUGEPAGE 14 -#endif - -#ifndef MADV_NOHUGEPAGE -#define MADV_NOHUGEPAGE 15 -#endif - -#ifndef MADV_DONTDUMP -#define MADV_DONTDUMP 16 -#endif - -#ifndef MADV_DODUMP -#define MADV_DODUMP 17 -#endif - - static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size, struct syscall_arg *arg) { @@ -170,6 +101,7 @@ static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size, P_MADV_BHV(SEQUENTIAL); P_MADV_BHV(WILLNEED); P_MADV_BHV(DONTNEED); + P_MADV_BHV(FREE); P_MADV_BHV(REMOVE); P_MADV_BHV(DONTFORK); P_MADV_BHV(DOFORK); diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 2e2d10022355..4c18271c71c9 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -495,7 +495,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser, if (!ins__is_call(dl->ins)) return false; - if (map_groups__find_ams(&target, NULL) || + if (map_groups__find_ams(&target) || map__rip_2objdump(target.map, target.map->map_ip(target.map, target.addr)) != dl->ops.target.addr) { diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 13d414384739..a6d5d248b8fb 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -69,8 +69,11 @@ static u32 hist_browser__nr_entries(struct hist_browser *hb) static void hist_browser__update_rows(struct hist_browser *hb) { struct ui_browser *browser = &hb->b; - u16 header_offset = hb->show_headers ? 1 : 0, index_row; + struct hists *hists = hb->hists; + struct perf_hpp_list *hpp_list = hists->hpp_list; + u16 header_offset, index_row; + header_offset = hb->show_headers ? hpp_list->nr_header_lines : 0; browser->rows = browser->height - header_offset; /* * Verify if we were at the last line and that line isn't @@ -99,8 +102,11 @@ static void hist_browser__refresh_dimensions(struct ui_browser *browser) static void hist_browser__gotorc(struct hist_browser *browser, int row, int column) { - u16 header_offset = browser->show_headers ? 1 : 0; + struct hists *hists = browser->hists; + struct perf_hpp_list *hpp_list = hists->hpp_list; + u16 header_offset; + header_offset = browser->show_headers ? hpp_list->nr_header_lines : 0; ui_browser__gotorc(&browser->b, row + header_offset, column); } @@ -1091,7 +1097,6 @@ static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...) ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent); ui_browser__printf(arg->b, "%s", hpp->buf); - advance_hpp(hpp, ret); return ret; } @@ -1496,7 +1501,9 @@ static int advance_hpp_check(struct perf_hpp *hpp, int inc) return hpp->size <= 0; } -static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf, size_t size) +static int +hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf, + size_t size, int line) { struct hists *hists = browser->hists; struct perf_hpp dummy_hpp = { @@ -1506,6 +1513,7 @@ static int hists_browser__scnprintf_headers(struct hist_browser *browser, char * struct perf_hpp_fmt *fmt; size_t ret = 0; int column = 0; + int span = 0; if (symbol_conf.use_callchain) { ret = scnprintf(buf, size, " "); @@ -1517,10 +1525,13 @@ static int hists_browser__scnprintf_headers(struct hist_browser *browser, char * if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll) continue; - ret = fmt->header(fmt, &dummy_hpp, hists); + ret = fmt->header(fmt, &dummy_hpp, hists, line, &span); if (advance_hpp_check(&dummy_hpp, ret)) break; + if (span) + continue; + ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " "); if (advance_hpp_check(&dummy_hpp, ret)) break; @@ -1554,7 +1565,7 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows if (column++ < browser->b.horiz_scroll) continue; - ret = fmt->header(fmt, &dummy_hpp, hists); + ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL); if (advance_hpp_check(&dummy_hpp, ret)) break; @@ -1591,7 +1602,7 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows } first_col = false; - ret = fmt->header(fmt, &dummy_hpp, hists); + ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL); dummy_hpp.buf[ret] = '\0'; start = trim(dummy_hpp.buf); @@ -1622,14 +1633,21 @@ static void hists_browser__hierarchy_headers(struct hist_browser *browser) static void hists_browser__headers(struct hist_browser *browser) { - char headers[1024]; + struct hists *hists = browser->hists; + struct perf_hpp_list *hpp_list = hists->hpp_list; - hists_browser__scnprintf_headers(browser, headers, - sizeof(headers)); + int line; - ui_browser__gotorc(&browser->b, 0, 0); - ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); - ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1); + for (line = 0; line < hpp_list->nr_header_lines; line++) { + char headers[1024]; + + hists_browser__scnprintf_headers(browser, headers, + sizeof(headers), line); + + ui_browser__gotorc(&browser->b, line, 0); + ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); + ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1); + } } static void hist_browser__show_headers(struct hist_browser *browser) @@ -1656,10 +1674,13 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser) u16 header_offset = 0; struct rb_node *nd; struct hist_browser *hb = container_of(browser, struct hist_browser, b); + struct hists *hists = hb->hists; if (hb->show_headers) { + struct perf_hpp_list *hpp_list = hists->hpp_list; + hist_browser__show_headers(hb); - header_offset = 1; + header_offset = hpp_list->nr_header_lines; } ui_browser__hists_init_top(browser); @@ -2054,10 +2075,10 @@ void hist_browser__init(struct hist_browser *browser, browser->b.use_navkeypressed = true; browser->show_headers = symbol_conf.show_hist_headers; - hists__for_each_format(hists, fmt) { - perf_hpp__reset_width(fmt, hists); + hists__for_each_format(hists, fmt) ++browser->b.columns; - } + + hists__reset_column_width(hists); } struct hist_browser *hist_browser__new(struct hists *hists) @@ -2418,8 +2439,6 @@ do_zoom_dso(struct hist_browser *browser, struct popup_action *act) browser->hists->dso_filter = NULL; ui_helpline__pop(); } else { - if (map == NULL) - return 0; ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"", __map__is_kernel(map) ? "the Kernel" : map->dso->short_name); browser->hists->dso_filter = map->dso; diff --git a/tools/perf/ui/browsers/map.c b/tools/perf/ui/browsers/map.c index 80912778bb6d..98a34664bb7e 100644 --- a/tools/perf/ui/browsers/map.c +++ b/tools/perf/ui/browsers/map.c @@ -52,9 +52,9 @@ static int map_browser__search(struct map_browser *browser) if (target[0] == '0' && tolower(target[1]) == 'x') { u64 addr = strtoull(target, NULL, 16); - sym = map__find_symbol(browser->map, addr, NULL); + sym = map__find_symbol(browser->map, addr); } else - sym = map__find_symbol_by_name(browser->map, target, NULL); + sym = map__find_symbol_by_name(browser->map, target); if (sym != NULL) { u32 *idx = symbol__browser_index(sym); diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index c5f3677f6679..a4f02de7c1b5 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c @@ -549,7 +549,7 @@ static void perf_gtk__show_hierarchy(GtkWidget *window, struct hists *hists, strcat(buf, "+"); first_col = false; - fmt->header(fmt, &hpp, hists); + fmt->header(fmt, &hpp, hists, 0, NULL); strcat(buf, ltrim(rtrim(hpp.buf))); } } diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 4274969ddc89..60c4a4d08374 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -230,7 +230,8 @@ static int hpp__width_fn(struct perf_hpp_fmt *fmt, } static int hpp__header_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, - struct hists *hists) + struct hists *hists, int line __maybe_unused, + int *span __maybe_unused) { int len = hpp__width_fn(fmt, hpp, hists); return scnprintf(hpp->buf, hpp->size, "%*s", len, fmt->name); @@ -441,6 +442,7 @@ struct perf_hpp_fmt perf_hpp__format[] = { struct perf_hpp_list perf_hpp_list = { .fields = LIST_HEAD_INIT(perf_hpp_list.fields), .sorts = LIST_HEAD_INIT(perf_hpp_list.sorts), + .nr_header_lines = 1, }; #undef HPP__COLOR_PRINT_FNS @@ -697,6 +699,21 @@ void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists) } } +void hists__reset_column_width(struct hists *hists) +{ + struct perf_hpp_fmt *fmt; + struct perf_hpp_list_node *node; + + hists__for_each_format(hists, fmt) + perf_hpp__reset_width(fmt, hists); + + /* hierarchy entries have their own hpp list */ + list_for_each_entry(node, &hists->hpp_formats, list) { + perf_hpp_list__for_each_format(&node->hpp, fmt) + perf_hpp__reset_width(fmt, hists); + } +} + void perf_hpp__set_user_width(const char *width_list_str) { struct perf_hpp_fmt *fmt; diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index f04a63112079..8e1840bff29d 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c @@ -528,8 +528,8 @@ static int print_hierarchy_indent(const char *sep, int indent, return fprintf(fp, "%-.*s", (indent - 2) * HIERARCHY_INDENT, line); } -static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp, - const char *sep, FILE *fp) +static int hists__fprintf_hierarchy_headers(struct hists *hists, + struct perf_hpp *hpp, FILE *fp) { bool first_node, first_col; int indent; @@ -538,6 +538,7 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp, unsigned header_width = 0; struct perf_hpp_fmt *fmt; struct perf_hpp_list_node *fmt_node; + const char *sep = symbol_conf.field_sep; indent = hists->nr_hpp_node; @@ -549,7 +550,7 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp, struct perf_hpp_list_node, list); perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { - fmt->header(fmt, hpp, hists); + fmt->header(fmt, hpp, hists, 0, NULL); fprintf(fp, "%s%s", hpp->buf, sep ?: " "); } @@ -569,7 +570,7 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp, header_width += fprintf(fp, "+"); first_col = false; - fmt->header(fmt, hpp, hists); + fmt->header(fmt, hpp, hists, 0, NULL); header_width += fprintf(fp, "%s", trim(hpp->buf)); } @@ -623,20 +624,28 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp, return 2; } -static int -hists__fprintf_hierarchy_headers(struct hists *hists, - struct perf_hpp *hpp, - FILE *fp) +static void fprintf_line(struct hists *hists, struct perf_hpp *hpp, + int line, FILE *fp) { - struct perf_hpp_list_node *fmt_node; struct perf_hpp_fmt *fmt; + const char *sep = symbol_conf.field_sep; + bool first = true; + int span = 0; - list_for_each_entry(fmt_node, &hists->hpp_formats, list) { - perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) - perf_hpp__reset_width(fmt, hists); - } + hists__for_each_format(hists, fmt) { + if (perf_hpp__should_skip(fmt, hists)) + continue; + + if (!first && !span) + fprintf(fp, "%s", sep ?: " "); + else + first = false; + + fmt->header(fmt, hpp, hists, line, &span); - return print_hierarchy_header(hists, hpp, symbol_conf.field_sep, fp); + if (!span) + fprintf(fp, "%s", hpp->buf); + } } static int @@ -644,28 +653,23 @@ hists__fprintf_standard_headers(struct hists *hists, struct perf_hpp *hpp, FILE *fp) { + struct perf_hpp_list *hpp_list = hists->hpp_list; struct perf_hpp_fmt *fmt; unsigned int width; const char *sep = symbol_conf.field_sep; bool first = true; - - hists__for_each_format(hists, fmt) { - if (perf_hpp__should_skip(fmt, hists)) - continue; - - if (!first) - fprintf(fp, "%s", sep ?: " "); - else - first = false; - - fmt->header(fmt, hpp, hists); - fprintf(fp, "%s", hpp->buf); + int line; + + for (line = 0; line < hpp_list->nr_header_lines; line++) { + /* first # is displayed one level up */ + if (line) + fprintf(fp, "# "); + fprintf_line(hists, hpp, line, fp); + fprintf(fp, "\n"); } - fprintf(fp, "\n"); - if (sep) - return 1; + return hpp_list->nr_header_lines; first = true; @@ -689,7 +693,7 @@ hists__fprintf_standard_headers(struct hists *hists, fprintf(fp, "\n"); fprintf(fp, "#\n"); - return 3; + return hpp_list->nr_header_lines + 2; } static int hists__fprintf_headers(struct hists *hists, FILE *fp) @@ -713,7 +717,6 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, int max_cols, float min_pcnt, FILE *fp, bool use_callchain) { - struct perf_hpp_fmt *fmt; struct rb_node *nd; size_t ret = 0; const char *sep = symbol_conf.field_sep; @@ -724,8 +727,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, init_rem_hits(); - hists__for_each_format(hists, fmt) - perf_hpp__reset_width(fmt, hists); + hists__reset_column_width(hists); if (symbol_conf.col_width_list_str) perf_hpp__set_user_width(symbol_conf.col_width_list_str); diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 91c5f6e1af59..96f99d608d00 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -1,5 +1,6 @@ libperf-y += alias.o libperf-y += annotate.o +libperf-y += block-range.o libperf-y += build-id.o libperf-y += config.o libperf-y += ctype.o @@ -98,6 +99,7 @@ endif libperf-$(CONFIG_DWARF) += probe-finder.o libperf-$(CONFIG_DWARF) += dwarf-aux.o +libperf-$(CONFIG_DWARF) += dwarf-regs.o libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o libperf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind-local.o diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 4024d309bb00..aeb5a441bd74 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -17,6 +17,7 @@ #include "debug.h" #include "annotate.h" #include "evsel.h" +#include "block-range.h" #include <regex.h> #include <pthread.h> #include <linux/bitops.h> @@ -53,7 +54,7 @@ int ins__scnprintf(struct ins *ins, char *bf, size_t size, return ins__raw_scnprintf(ins, bf, size, ops); } -static int call__parse(struct ins_operands *ops) +static int call__parse(struct ins_operands *ops, struct map *map) { char *endptr, *tok, *name; @@ -81,16 +82,16 @@ static int call__parse(struct ins_operands *ops) return ops->target.name == NULL ? -1 : 0; indirect_call: - tok = strchr(endptr, '('); - if (tok != NULL) { - ops->target.addr = 0; + tok = strchr(endptr, '*'); + if (tok == NULL) { + struct symbol *sym = map__find_symbol(map, map->map_ip(map, ops->target.addr)); + if (sym != NULL) + ops->target.name = strdup(sym->name); + else + ops->target.addr = 0; return 0; } - tok = strchr(endptr, '*'); - if (tok == NULL) - return -1; - ops->target.addr = strtoull(tok + 1, NULL, 16); return 0; } @@ -117,7 +118,7 @@ bool ins__is_call(const struct ins *ins) return ins->ops == &call_ops; } -static int jump__parse(struct ins_operands *ops) +static int jump__parse(struct ins_operands *ops, struct map *map __maybe_unused) { const char *s = strchr(ops->raw, '+'); @@ -172,7 +173,7 @@ static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep) return 0; } -static int lock__parse(struct ins_operands *ops) +static int lock__parse(struct ins_operands *ops, struct map *map) { char *name; @@ -193,7 +194,7 @@ static int lock__parse(struct ins_operands *ops) return 0; if (ops->locked.ins->ops->parse && - ops->locked.ins->ops->parse(ops->locked.ops) < 0) + ops->locked.ins->ops->parse(ops->locked.ops, map) < 0) goto out_free_ops; return 0; @@ -236,7 +237,7 @@ static struct ins_ops lock_ops = { .scnprintf = lock__scnprintf, }; -static int mov__parse(struct ins_operands *ops) +static int mov__parse(struct ins_operands *ops, struct map *map __maybe_unused) { char *s = strchr(ops->raw, ','), *target, *comment, prev; @@ -303,7 +304,7 @@ static struct ins_ops mov_ops = { .scnprintf = mov__scnprintf, }; -static int dec__parse(struct ins_operands *ops) +static int dec__parse(struct ins_operands *ops, struct map *map __maybe_unused) { char *target, *comment, *s, prev; @@ -491,13 +492,6 @@ static struct ins *ins__find(const char *name) return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__key_cmp); } -int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym) -{ - struct annotation *notes = symbol__annotation(sym); - pthread_mutex_init(¬es->lock, NULL); - return 0; -} - int symbol__alloc_hist(struct symbol *sym) { struct annotation *notes = symbol__annotation(sym); @@ -715,7 +709,7 @@ int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip) return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip); } -static void disasm_line__init_ins(struct disasm_line *dl) +static void disasm_line__init_ins(struct disasm_line *dl, struct map *map) { dl->ins = ins__find(dl->name); @@ -725,7 +719,7 @@ static void disasm_line__init_ins(struct disasm_line *dl) if (!dl->ins->ops) return; - if (dl->ins->ops->parse && dl->ins->ops->parse(&dl->ops) < 0) + if (dl->ins->ops->parse && dl->ins->ops->parse(&dl->ops, map) < 0) dl->ins = NULL; } @@ -767,7 +761,8 @@ out_free_name: } static struct disasm_line *disasm_line__new(s64 offset, char *line, - size_t privsize, int line_nr) + size_t privsize, int line_nr, + struct map *map) { struct disasm_line *dl = zalloc(sizeof(*dl) + privsize); @@ -782,7 +777,7 @@ static struct disasm_line *disasm_line__new(s64 offset, char *line, if (disasm_line__parse(dl->line, &dl->name, &dl->ops.raw) < 0) goto out_free_line; - disasm_line__init_ins(dl); + disasm_line__init_ins(dl, map); } } @@ -866,6 +861,89 @@ double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, return percent; } +static const char *annotate__address_color(struct block_range *br) +{ + double cov = block_range__coverage(br); + + if (cov >= 0) { + /* mark red for >75% coverage */ + if (cov > 0.75) + return PERF_COLOR_RED; + + /* mark dull for <1% coverage */ + if (cov < 0.01) + return PERF_COLOR_NORMAL; + } + + return PERF_COLOR_MAGENTA; +} + +static const char *annotate__asm_color(struct block_range *br) +{ + double cov = block_range__coverage(br); + + if (cov >= 0) { + /* mark dull for <1% coverage */ + if (cov < 0.01) + return PERF_COLOR_NORMAL; + } + + return PERF_COLOR_BLUE; +} + +static void annotate__branch_printf(struct block_range *br, u64 addr) +{ + bool emit_comment = true; + + if (!br) + return; + +#if 1 + if (br->is_target && br->start == addr) { + struct block_range *branch = br; + double p; + + /* + * Find matching branch to our target. + */ + while (!branch->is_branch) + branch = block_range__next(branch); + + p = 100 *(double)br->entry / branch->coverage; + + if (p > 0.1) { + if (emit_comment) { + emit_comment = false; + printf("\t#"); + } + + /* + * The percentage of coverage joined at this target in relation + * to the next branch. + */ + printf(" +%.2f%%", p); + } + } +#endif + if (br->is_branch && br->end == addr) { + double p = 100*(double)br->taken / br->coverage; + + if (p > 0.1) { + if (emit_comment) { + emit_comment = false; + printf("\t#"); + } + + /* + * The percentage of coverage leaving at this branch, and + * its prediction ratio. + */ + printf(" -%.2f%% (p:%.2f%%)", p, 100*(double)br->pred / br->taken); + } + } +} + + static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start, struct perf_evsel *evsel, u64 len, int min_pcnt, int printed, int max_lines, struct disasm_line *queue) @@ -885,6 +963,7 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st s64 offset = dl->offset; const u64 addr = start + offset; struct disasm_line *next; + struct block_range *br; next = disasm__get_next_ip_line(¬es->src->source, dl); @@ -954,8 +1033,12 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st } printf(" : "); - color_fprintf(stdout, PERF_COLOR_MAGENTA, " %" PRIx64 ":", addr); - color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line); + + br = block_range__find(addr); + color_fprintf(stdout, annotate__address_color(br), " %" PRIx64 ":", addr); + color_fprintf(stdout, annotate__asm_color(br), "%s", dl->line); + annotate__branch_printf(br, addr); + printf("\n"); if (ppercents != &percent) free(ppercents); @@ -1066,7 +1149,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, parsed_line = tmp2 + 1; } - dl = disasm_line__new(offset, parsed_line, privsize, *line_nr); + dl = disasm_line__new(offset, parsed_line, privsize, *line_nr, map); free(line); (*line_nr)++; @@ -1084,7 +1167,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, .addr = dl->ops.target.addr, }; - if (!map_groups__find_ams(&target, NULL) && + if (!map_groups__find_ams(&target) && target.sym->start == target.al_addr) dl->ops.target.name = strdup(target.sym->name); } @@ -1162,53 +1245,60 @@ int symbol__strerror_disassemble(struct symbol *sym __maybe_unused, struct map * return 0; } -int symbol__disassemble(struct symbol *sym, struct map *map, size_t privsize) +static int dso__disassemble_filename(struct dso *dso, char *filename, size_t filename_size) { - struct dso *dso = map->dso; - char *filename = dso__build_id_filename(dso, NULL, 0); - bool free_filename = true; - char command[PATH_MAX * 2]; - FILE *file; - int err = 0; - char symfs_filename[PATH_MAX]; - struct kcore_extract kce; - bool delete_extract = false; - int stdout_fd[2]; - int lineno = 0; - int nline; - pid_t pid; + char linkname[PATH_MAX]; + char *build_id_filename; - if (filename) - symbol__join_symfs(symfs_filename, filename); + if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS && + !dso__is_kcore(dso)) + return SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX; - if (filename == NULL) { + build_id_filename = dso__build_id_filename(dso, NULL, 0); + if (build_id_filename) { + __symbol__join_symfs(filename, filename_size, build_id_filename); + free(build_id_filename); + } else { if (dso->has_build_id) return ENOMEM; goto fallback; - } else if (dso__is_kcore(dso) || - readlink(symfs_filename, command, sizeof(command)) < 0 || - strstr(command, DSO__NAME_KALLSYMS) || - access(symfs_filename, R_OK)) { - free(filename); + } + + if (dso__is_kcore(dso) || + readlink(filename, linkname, sizeof(linkname)) < 0 || + strstr(linkname, DSO__NAME_KALLSYMS) || + access(filename, R_OK)) { fallback: /* * If we don't have build-ids or the build-id file isn't in the * cache, or is just a kallsyms file, well, lets hope that this * DSO is the same as when 'perf record' ran. */ - filename = (char *)dso->long_name; - symbol__join_symfs(symfs_filename, filename); - free_filename = false; + __symbol__join_symfs(filename, filename_size, dso->long_name); } - if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS && - !dso__is_kcore(dso)) { - err = SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX; - goto out_free_filename; - } + return 0; +} + +int symbol__disassemble(struct symbol *sym, struct map *map, size_t privsize) +{ + struct dso *dso = map->dso; + char command[PATH_MAX * 2]; + FILE *file; + char symfs_filename[PATH_MAX]; + struct kcore_extract kce; + bool delete_extract = false; + int stdout_fd[2]; + int lineno = 0; + int nline; + pid_t pid; + int err = dso__disassemble_filename(dso, symfs_filename, sizeof(symfs_filename)); + + if (err) + return err; pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__, - filename, sym->name, map->unmap_ip(map, sym->start), + symfs_filename, sym->name, map->unmap_ip(map, sym->start), map->unmap_ip(map, sym->end)); pr_debug("annotating [%p] %30s : [%p] %30s\n", @@ -1223,11 +1313,6 @@ fallback: delete_extract = true; strlcpy(symfs_filename, kce.extract_filename, sizeof(symfs_filename)); - if (free_filename) { - free(filename); - free_filename = false; - } - filename = symfs_filename; } } else if (dso__needs_decompress(dso)) { char tmp[PATH_MAX]; @@ -1236,14 +1321,14 @@ fallback: bool ret; if (kmod_path__parse_ext(&m, symfs_filename)) - goto out_free_filename; + goto out; snprintf(tmp, PATH_MAX, "/tmp/perf-kmod-XXXXXX"); fd = mkstemp(tmp); if (fd < 0) { free(m.ext); - goto out_free_filename; + goto out; } ret = decompress_to_file(m.ext, symfs_filename, fd); @@ -1255,7 +1340,7 @@ fallback: close(fd); if (!ret) - goto out_free_filename; + goto out; strcpy(symfs_filename, tmp); } @@ -1271,7 +1356,7 @@ fallback: map__rip_2objdump(map, sym->end), symbol_conf.annotate_asm_raw ? "" : "--no-show-raw", symbol_conf.annotate_src ? "-S" : "", - symfs_filename, filename); + symfs_filename, symfs_filename); pr_debug("Executing: %s\n", command); @@ -1333,11 +1418,10 @@ out_remove_tmp: if (dso__needs_decompress(dso)) unlink(symfs_filename); -out_free_filename: + if (delete_extract) kcore_extract__delete(&kce); - if (free_filename) - free(filename); +out: return err; out_close_stdout: diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index f67ccb027561..5bbcec173b82 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -36,7 +36,7 @@ struct ins_operands { struct ins_ops { void (*free)(struct ins_operands *ops); - int (*parse)(struct ins_operands *ops); + int (*parse)(struct ins_operands *ops, struct map *map); int (*scnprintf)(struct ins *ins, char *bf, size_t size, struct ins_operands *ops); }; @@ -130,6 +130,7 @@ struct annotated_source { struct annotation { pthread_mutex_t lock; + u64 max_coverage; struct annotated_source *src; }; @@ -177,7 +178,6 @@ enum symbol_disassemble_errno { int symbol__strerror_disassemble(struct symbol *sym, struct map *map, int errnum, char *buf, size_t buflen); -int symbol__annotate_init(struct map *map, struct symbol *sym); int symbol__annotate_printf(struct symbol *sym, struct map *map, struct perf_evsel *evsel, bool full_paths, int min_pcnt, int max_lines, int context); diff --git a/tools/perf/util/block-range.c b/tools/perf/util/block-range.c new file mode 100644 index 000000000000..7b3e1d75d803 --- /dev/null +++ b/tools/perf/util/block-range.c @@ -0,0 +1,328 @@ +#include "block-range.h" +#include "annotate.h" + +struct { + struct rb_root root; + u64 blocks; +} block_ranges; + +static void block_range__debug(void) +{ + /* + * XXX still paranoid for now; see if we can make this depend on + * DEBUG=1 builds. + */ +#if 1 + struct rb_node *rb; + u64 old = 0; /* NULL isn't executable */ + + for (rb = rb_first(&block_ranges.root); rb; rb = rb_next(rb)) { + struct block_range *entry = rb_entry(rb, struct block_range, node); + + assert(old < entry->start); + assert(entry->start <= entry->end); /* single instruction block; jump to a jump */ + + old = entry->end; + } +#endif +} + +struct block_range *block_range__find(u64 addr) +{ + struct rb_node **p = &block_ranges.root.rb_node; + struct rb_node *parent = NULL; + struct block_range *entry; + + while (*p != NULL) { + parent = *p; + entry = rb_entry(parent, struct block_range, node); + + if (addr < entry->start) + p = &parent->rb_left; + else if (addr > entry->end) + p = &parent->rb_right; + else + return entry; + } + + return NULL; +} + +static inline void rb_link_left_of_node(struct rb_node *left, struct rb_node *node) +{ + struct rb_node **p = &node->rb_left; + while (*p) { + node = *p; + p = &node->rb_right; + } + rb_link_node(left, node, p); +} + +static inline void rb_link_right_of_node(struct rb_node *right, struct rb_node *node) +{ + struct rb_node **p = &node->rb_right; + while (*p) { + node = *p; + p = &node->rb_left; + } + rb_link_node(right, node, p); +} + +/** + * block_range__create + * @start: branch target starting this basic block + * @end: branch ending this basic block + * + * Create all the required block ranges to precisely span the given range. + */ +struct block_range_iter block_range__create(u64 start, u64 end) +{ + struct rb_node **p = &block_ranges.root.rb_node; + struct rb_node *n, *parent = NULL; + struct block_range *next, *entry = NULL; + struct block_range_iter iter = { NULL, NULL }; + + while (*p != NULL) { + parent = *p; + entry = rb_entry(parent, struct block_range, node); + + if (start < entry->start) + p = &parent->rb_left; + else if (start > entry->end) + p = &parent->rb_right; + else + break; + } + + /* + * Didn't find anything.. there's a hole at @start, however @end might + * be inside/behind the next range. + */ + if (!*p) { + if (!entry) /* tree empty */ + goto do_whole; + + /* + * If the last node is before, advance one to find the next. + */ + n = parent; + if (entry->end < start) { + n = rb_next(n); + if (!n) + goto do_whole; + } + next = rb_entry(n, struct block_range, node); + + if (next->start <= end) { /* add head: [start...][n->start...] */ + struct block_range *head = malloc(sizeof(struct block_range)); + if (!head) + return iter; + + *head = (struct block_range){ + .start = start, + .end = next->start - 1, + .is_target = 1, + .is_branch = 0, + }; + + rb_link_left_of_node(&head->node, &next->node); + rb_insert_color(&head->node, &block_ranges.root); + block_range__debug(); + + iter.start = head; + goto do_tail; + } + +do_whole: + /* + * The whole [start..end] range is non-overlapping. + */ + entry = malloc(sizeof(struct block_range)); + if (!entry) + return iter; + + *entry = (struct block_range){ + .start = start, + .end = end, + .is_target = 1, + .is_branch = 1, + }; + + rb_link_node(&entry->node, parent, p); + rb_insert_color(&entry->node, &block_ranges.root); + block_range__debug(); + + iter.start = entry; + iter.end = entry; + goto done; + } + + /* + * We found a range that overlapped with ours, split if needed. + */ + if (entry->start < start) { /* split: [e->start...][start...] */ + struct block_range *head = malloc(sizeof(struct block_range)); + if (!head) + return iter; + + *head = (struct block_range){ + .start = entry->start, + .end = start - 1, + .is_target = entry->is_target, + .is_branch = 0, + + .coverage = entry->coverage, + .entry = entry->entry, + }; + + entry->start = start; + entry->is_target = 1; + entry->entry = 0; + + rb_link_left_of_node(&head->node, &entry->node); + rb_insert_color(&head->node, &block_ranges.root); + block_range__debug(); + + } else if (entry->start == start) + entry->is_target = 1; + + iter.start = entry; + +do_tail: + /* + * At this point we've got: @iter.start = [@start...] but @end can still be + * inside or beyond it. + */ + entry = iter.start; + for (;;) { + /* + * If @end is inside @entry, split. + */ + if (end < entry->end) { /* split: [...end][...e->end] */ + struct block_range *tail = malloc(sizeof(struct block_range)); + if (!tail) + return iter; + + *tail = (struct block_range){ + .start = end + 1, + .end = entry->end, + .is_target = 0, + .is_branch = entry->is_branch, + + .coverage = entry->coverage, + .taken = entry->taken, + .pred = entry->pred, + }; + + entry->end = end; + entry->is_branch = 1; + entry->taken = 0; + entry->pred = 0; + + rb_link_right_of_node(&tail->node, &entry->node); + rb_insert_color(&tail->node, &block_ranges.root); + block_range__debug(); + + iter.end = entry; + goto done; + } + + /* + * If @end matches @entry, done + */ + if (end == entry->end) { + entry->is_branch = 1; + iter.end = entry; + goto done; + } + + next = block_range__next(entry); + if (!next) + goto add_tail; + + /* + * If @end is in beyond @entry but not inside @next, add tail. + */ + if (end < next->start) { /* add tail: [...e->end][...end] */ + struct block_range *tail; +add_tail: + tail = malloc(sizeof(struct block_range)); + if (!tail) + return iter; + + *tail = (struct block_range){ + .start = entry->end + 1, + .end = end, + .is_target = 0, + .is_branch = 1, + }; + + rb_link_right_of_node(&tail->node, &entry->node); + rb_insert_color(&tail->node, &block_ranges.root); + block_range__debug(); + + iter.end = tail; + goto done; + } + + /* + * If there is a hole between @entry and @next, fill it. + */ + if (entry->end + 1 != next->start) { + struct block_range *hole = malloc(sizeof(struct block_range)); + if (!hole) + return iter; + + *hole = (struct block_range){ + .start = entry->end + 1, + .end = next->start - 1, + .is_target = 0, + .is_branch = 0, + }; + + rb_link_left_of_node(&hole->node, &next->node); + rb_insert_color(&hole->node, &block_ranges.root); + block_range__debug(); + } + + entry = next; + } + +done: + assert(iter.start->start == start && iter.start->is_target); + assert(iter.end->end == end && iter.end->is_branch); + + block_ranges.blocks++; + + return iter; +} + + +/* + * Compute coverage as: + * + * br->coverage / br->sym->max_coverage + * + * This ensures each symbol has a 100% spot, to reflect that each symbol has a + * most covered section. + * + * Returns [0-1] for coverage and -1 if we had no data what so ever or the + * symbol does not exist. + */ +double block_range__coverage(struct block_range *br) +{ + struct symbol *sym; + + if (!br) { + if (block_ranges.blocks) + return 0; + + return -1; + } + + sym = br->sym; + if (!sym) + return -1; + + return (double)br->coverage / symbol__annotation(sym)->max_coverage; +} diff --git a/tools/perf/util/block-range.h b/tools/perf/util/block-range.h new file mode 100644 index 000000000000..a8c841381131 --- /dev/null +++ b/tools/perf/util/block-range.h @@ -0,0 +1,71 @@ +#ifndef __PERF_BLOCK_RANGE_H +#define __PERF_BLOCK_RANGE_H + +#include "symbol.h" + +/* + * struct block_range - non-overlapping parts of basic blocks + * @node: treenode + * @start: inclusive start of range + * @end: inclusive end of range + * @is_target: @start is a jump target + * @is_branch: @end is a branch instruction + * @coverage: number of blocks that cover this range + * @taken: number of times the branch is taken (requires @is_branch) + * @pred: number of times the taken branch was predicted + */ +struct block_range { + struct rb_node node; + + struct symbol *sym; + + u64 start; + u64 end; + + int is_target, is_branch; + + u64 coverage; + u64 entry; + u64 taken; + u64 pred; +}; + +static inline struct block_range *block_range__next(struct block_range *br) +{ + struct rb_node *n = rb_next(&br->node); + if (!n) + return NULL; + return rb_entry(n, struct block_range, node); +} + +struct block_range_iter { + struct block_range *start; + struct block_range *end; +}; + +static inline struct block_range *block_range_iter(struct block_range_iter *iter) +{ + return iter->start; +} + +static inline bool block_range_iter__next(struct block_range_iter *iter) +{ + if (iter->start == iter->end) + return false; + + iter->start = block_range__next(iter->start); + return true; +} + +static inline bool block_range_iter__valid(struct block_range_iter *iter) +{ + if (!iter->start || !iter->end) + return false; + return true; +} + +extern struct block_range *block_range__find(u64 addr); +extern struct block_range_iter block_range__create(u64 start, u64 end); +extern double block_range__coverage(struct block_range *br); + +#endif /* __PERF_BLOCK_RANGE_H */ diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index 1f12e4e40006..2b2c9b82f5ab 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c @@ -531,7 +531,7 @@ static int map_prologue(struct perf_probe_event *pev, int *mapping, ptevs = malloc(array_sz); if (!ptevs) { - pr_debug("No ehough memory: alloc ptevs failed\n"); + pr_debug("No enough memory: alloc ptevs failed\n"); return -ENOMEM; } diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 8c4212abd19b..c1838b643108 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c @@ -6,6 +6,7 @@ #include <stdarg.h> #include <stdio.h> #include <api/debug.h> +#include <linux/time64.h> #include "cache.h" #include "color.h" @@ -14,9 +15,6 @@ #include "util.h" #include "target.h" -#define NSECS_PER_SEC 1000000000ULL -#define NSECS_PER_USEC 1000ULL - int verbose; bool dump_trace = false, quiet = false; int debug_ordered_events; @@ -54,9 +52,9 @@ static int veprintf_time(u64 t, const char *fmt, va_list args) int ret = 0; u64 secs, usecs, nsecs = t; - secs = nsecs / NSECS_PER_SEC; - nsecs -= secs * NSECS_PER_SEC; - usecs = nsecs / NSECS_PER_USEC; + secs = nsecs / NSEC_PER_SEC; + nsecs -= secs * NSEC_PER_SEC; + usecs = nsecs / NSEC_PER_USEC; ret = fprintf(stderr, "[%13" PRIu64 ".%06" PRIu64 "] ", secs, usecs); diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 774f6ec884d5..d2c6cdd9d42b 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -363,6 +363,9 @@ static int __open_dso(struct dso *dso, struct machine *machine) return -EINVAL; } + if (!is_regular_file(name)) + return -EINVAL; + fd = do_open(name); free(name); return fd; diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index a347b19c961a..faec899435f2 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -1085,3 +1085,182 @@ int die_get_var_range(Dwarf_Die *sp_die __maybe_unused, return -ENOTSUP; } #endif + +/* + * die_has_loclist - Check if DW_AT_location of @vr_die is a location list + * @vr_die: a variable DIE + */ +static bool die_has_loclist(Dwarf_Die *vr_die) +{ + Dwarf_Attribute loc; + int tag = dwarf_tag(vr_die); + + if (tag != DW_TAG_formal_parameter && + tag != DW_TAG_variable) + return false; + + return (dwarf_attr_integrate(vr_die, DW_AT_location, &loc) && + dwarf_whatform(&loc) == DW_FORM_sec_offset); +} + +/* + * die_is_optimized_target - Check if target program is compiled with + * optimization + * @cu_die: a CU DIE + * + * For any object in given CU whose DW_AT_location is a location list, + * target program is compiled with optimization. This is applicable to + * clang as well. + */ +bool die_is_optimized_target(Dwarf_Die *cu_die) +{ + Dwarf_Die tmp_die; + + if (die_has_loclist(cu_die)) + return true; + + if (!dwarf_child(cu_die, &tmp_die) && + die_is_optimized_target(&tmp_die)) + return true; + + if (!dwarf_siblingof(cu_die, &tmp_die) && + die_is_optimized_target(&tmp_die)) + return true; + + return false; +} + +/* + * die_search_idx - Search index of given line address + * @lines: Line records of single CU + * @nr_lines: Number of @lines + * @addr: address we are looking for + * @idx: index to be set by this function (return value) + * + * Search for @addr by looping over every lines of CU. If address + * matches, set index of that line in @idx. Note that single source + * line can have multiple line records. i.e. single source line can + * have multiple index. + */ +static bool die_search_idx(Dwarf_Lines *lines, unsigned long nr_lines, + Dwarf_Addr addr, unsigned long *idx) +{ + unsigned long i; + Dwarf_Addr tmp; + + for (i = 0; i < nr_lines; i++) { + if (dwarf_lineaddr(dwarf_onesrcline(lines, i), &tmp)) + return false; + + if (tmp == addr) { + *idx = i; + return true; + } + } + return false; +} + +/* + * die_get_postprologue_addr - Search next address after function prologue + * @entrypc_idx: entrypc index + * @lines: Line records of single CU + * @nr_lines: Number of @lines + * @hignpc: high PC address of function + * @postprologue_addr: Next address after function prologue (return value) + * + * Look for prologue-end marker. If there is no explicit marker, return + * address of next line record or next source line. + */ +static bool die_get_postprologue_addr(unsigned long entrypc_idx, + Dwarf_Lines *lines, + unsigned long nr_lines, + Dwarf_Addr highpc, + Dwarf_Addr *postprologue_addr) +{ + unsigned long i; + int entrypc_lno, lno; + Dwarf_Line *line; + Dwarf_Addr addr; + bool p_end; + + /* entrypc_lno is actual source line number */ + line = dwarf_onesrcline(lines, entrypc_idx); + if (dwarf_lineno(line, &entrypc_lno)) + return false; + + for (i = entrypc_idx; i < nr_lines; i++) { + line = dwarf_onesrcline(lines, i); + + if (dwarf_lineaddr(line, &addr) || + dwarf_lineno(line, &lno) || + dwarf_lineprologueend(line, &p_end)) + return false; + + /* highpc is exclusive. [entrypc,highpc) */ + if (addr >= highpc) + break; + + /* clang supports prologue-end marker */ + if (p_end) + break; + + /* Actual next line in source */ + if (lno != entrypc_lno) + break; + + /* + * Single source line can have multiple line records. + * For Example, + * void foo() { printf("hello\n"); } + * contains two line records. One points to declaration and + * other points to printf() line. Variable 'lno' won't get + * incremented in this case but 'i' will. + */ + if (i != entrypc_idx) + break; + } + + dwarf_lineaddr(line, postprologue_addr); + if (*postprologue_addr >= highpc) + dwarf_lineaddr(dwarf_onesrcline(lines, i - 1), + postprologue_addr); + + return true; +} + +/* + * die_skip_prologue - Use next address after prologue as probe location + * @sp_die: a subprogram DIE + * @cu_die: a CU DIE + * @entrypc: entrypc of the function + * + * Function prologue prepares stack and registers before executing function + * logic. When target program is compiled without optimization, function + * parameter information is only valid after prologue. When we probe entrypc + * of the function, and try to record function parameter, it contains + * garbage value. + */ +void die_skip_prologue(Dwarf_Die *sp_die, Dwarf_Die *cu_die, + Dwarf_Addr *entrypc) +{ + size_t nr_lines = 0; + unsigned long entrypc_idx = 0; + Dwarf_Lines *lines = NULL; + Dwarf_Addr postprologue_addr; + Dwarf_Addr highpc; + + if (dwarf_highpc(sp_die, &highpc)) + return; + + if (dwarf_getsrclines(cu_die, &lines, &nr_lines)) + return; + + if (!die_search_idx(lines, nr_lines, *entrypc, &entrypc_idx)) + return; + + if (!die_get_postprologue_addr(entrypc_idx, lines, nr_lines, + highpc, &postprologue_addr)) + return; + + *entrypc = postprologue_addr; +} diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index dc0ce1adb075..8b6d2f83af02 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h @@ -125,4 +125,12 @@ int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf); /* Get the name and type of given variable DIE, stored as "type\tname" */ int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf); int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf); + +/* Check if target program is compiled with optimization */ +bool die_is_optimized_target(Dwarf_Die *cu_die); + +/* Use next address after prologue as probe location */ +void die_skip_prologue(Dwarf_Die *sp_die, Dwarf_Die *cu_die, + Dwarf_Addr *entrypc); + #endif diff --git a/tools/perf/util/dwarf-regs.c b/tools/perf/util/dwarf-regs.c new file mode 100644 index 000000000000..62bc4a86a970 --- /dev/null +++ b/tools/perf/util/dwarf-regs.c @@ -0,0 +1,59 @@ +/* + * dwarf-regs.c : Mapping of DWARF debug register numbers into register names. + * + * Written by: Masami Hiramatsu <mhiramat@kernel.org> + */ + +#include <util.h> +#include <debug.h> +#include <dwarf-regs.h> +#include <elf.h> + +#ifndef EM_AARCH64 +#define EM_AARCH64 183 /* ARM 64 bit */ +#endif + +/* Define const char * {arch}_register_tbl[] */ +#define DEFINE_DWARF_REGSTR_TABLE +#include "../arch/x86/include/dwarf-regs-table.h" +#include "../arch/arm/include/dwarf-regs-table.h" +#include "../arch/arm64/include/dwarf-regs-table.h" +#include "../arch/sh/include/dwarf-regs-table.h" +#include "../arch/powerpc/include/dwarf-regs-table.h" +#include "../arch/s390/include/dwarf-regs-table.h" +#include "../arch/sparc/include/dwarf-regs-table.h" +#include "../arch/xtensa/include/dwarf-regs-table.h" + +#define __get_dwarf_regstr(tbl, n) (((n) < ARRAY_SIZE(tbl)) ? (tbl)[(n)] : NULL) + +/* Return architecture dependent register string (for kprobe-tracer) */ +const char *get_dwarf_regstr(unsigned int n, unsigned int machine) +{ + switch (machine) { + case EM_NONE: /* Generic arch - use host arch */ + return get_arch_regstr(n); + case EM_386: + return __get_dwarf_regstr(x86_32_regstr_tbl, n); + case EM_X86_64: + return __get_dwarf_regstr(x86_64_regstr_tbl, n); + case EM_ARM: + return __get_dwarf_regstr(arm_regstr_tbl, n); + case EM_AARCH64: + return __get_dwarf_regstr(aarch64_regstr_tbl, n); + case EM_SH: + return __get_dwarf_regstr(sh_regstr_tbl, n); + case EM_S390: + return __get_dwarf_regstr(s390_regstr_tbl, n); + case EM_PPC: + case EM_PPC64: + return __get_dwarf_regstr(powerpc_regstr_tbl, n); + case EM_SPARC: + case EM_SPARCV9: + return __get_dwarf_regstr(sparc_regstr_tbl, n); + case EM_XTENSA: + return __get_dwarf_regstr(xtensa_regstr_tbl, n); + default: + pr_err("ELF MACHINE %x is not supported.\n", machine); + } + return NULL; +} diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index e20438b784be..2880e2226fdb 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -1,5 +1,6 @@ #include <linux/types.h> -#include <sys/mman.h> +#include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */ +#include <api/fs/fs.h> #include "event.h" #include "debug.h" #include "hist.h" @@ -248,6 +249,8 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool, bool truncation = false; unsigned long long timeout = proc_map_timeout * 1000000ULL; int rc = 0; + const char *hugetlbfs_mnt = hugetlbfs__mountpoint(); + int hugetlbfs_mnt_len = hugetlbfs_mnt ? strlen(hugetlbfs_mnt) : 0; if (machine__is_default_guest(machine)) return 0; @@ -343,6 +346,11 @@ out: if (!strcmp(execname, "")) strcpy(execname, anonstr); + if (!strncmp(execname, hugetlbfs_mnt, hugetlbfs_mnt_len)) { + strcpy(execname, anonstr); + event->mmap2.flags |= MAP_HUGETLB; + } + size = strlen(execname) + 1; memcpy(event->mmap2.filename, execname, size); size = PERF_ALIGN(size, sizeof(u64)); @@ -1286,7 +1294,7 @@ try_again: * must be done prior to using kernel maps. */ if (load_map) - map__load(al->map, machine->symbol_filter); + map__load(al->map); al->addr = al->map->map_ip(al->map, al->addr); } } @@ -1297,8 +1305,7 @@ void thread__find_addr_location(struct thread *thread, { thread__find_addr_map(thread, cpumode, type, addr, al); if (al->map != NULL) - al->sym = map__find_symbol(al->map, al->addr, - thread->mg->machine->symbol_filter); + al->sym = map__find_symbol(al->map, al->addr); else al->sym = NULL; } @@ -1359,8 +1366,7 @@ int machine__resolve(struct machine *machine, struct addr_location *al, al->filtered |= (1 << HIST_FILTER__DSO); } - al->sym = map__find_symbol(al->map, al->addr, - machine->symbol_filter); + al->sym = map__find_symbol(al->map, al->addr); } if (symbol_conf.sym_list && @@ -1416,5 +1422,5 @@ void thread__resolve(struct thread *thread, struct addr_location *al, al->sym = NULL; if (al->map) - al->sym = map__find_symbol(al->map, al->addr, NULL); + al->sym = map__find_symbol(al->map, al->addr); } diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 097b3ed77fdd..ea34c5a32c11 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -1032,16 +1032,18 @@ perf_evlist__should_poll(struct perf_evlist *evlist __maybe_unused, } static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, - struct mmap_params *mp, int cpu, + struct mmap_params *mp, int cpu_idx, int thread, int *_output, int *_output_backward) { struct perf_evsel *evsel; int revent; + int evlist_cpu = cpu_map__cpu(evlist->cpus, cpu_idx); evlist__for_each_entry(evlist, evsel) { struct perf_mmap *maps = evlist->mmap; int *output = _output; int fd; + int cpu; if (evsel->attr.write_backward) { output = _output_backward; @@ -1060,6 +1062,10 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, if (evsel->system_wide && thread) continue; + cpu = cpu_map__idx(evsel->cpus, evlist_cpu); + if (cpu == -1) + continue; + fd = FD(evsel, cpu, thread); if (*output == -1) { diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 4d44129e050b..323806082c58 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -46,6 +46,7 @@ enum { PERF_EVSEL__CONFIG_TERM_INHERIT, PERF_EVSEL__CONFIG_TERM_MAX_STACK, PERF_EVSEL__CONFIG_TERM_OVERWRITE, + PERF_EVSEL__CONFIG_TERM_DRV_CFG, PERF_EVSEL__CONFIG_TERM_MAX, }; @@ -57,6 +58,7 @@ struct perf_evsel_config_term { u64 freq; bool time; char *callgraph; + char *drv_cfg; u64 stack_user; int max_stack; bool inherit; diff --git a/tools/perf/util/evsel_fprintf.c b/tools/perf/util/evsel_fprintf.c index 3674e77ad640..9111e0666950 100644 --- a/tools/perf/util/evsel_fprintf.c +++ b/tools/perf/util/evsel_fprintf.c @@ -122,7 +122,7 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment, if (!node) break; - if (node->sym && node->sym->ignore) + if (node->sym && node->sym->idle) goto next; printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " "); @@ -181,7 +181,7 @@ int sample__fprintf_sym(struct perf_sample *sample, struct addr_location *al, if (cursor != NULL) { printed += sample__fprintf_callchain(sample, left_alignment, print_opts, cursor, fp); - } else if (!(al->sym && al->sym->ignore)) { + } else if (!(al->sym && al->sym->idle)) { printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " "); if (print_ip) diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 8f0db4007282..85dd0db0a127 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -828,8 +828,7 @@ static int write_group_desc(int fd, struct perf_header *h __maybe_unused, * default get_cpuid(): nothing gets recorded * actual implementation must be in arch/$(ARCH)/util/header.c */ -int __attribute__ ((weak)) get_cpuid(char *buffer __maybe_unused, - size_t sz __maybe_unused) +int __weak get_cpuid(char *buffer __maybe_unused, size_t sz __maybe_unused) { return -1; } diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index de15dbcdcecf..b02992efb513 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -177,8 +177,10 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) hists__new_col_len(hists, HISTC_LOCAL_WEIGHT, 12); hists__new_col_len(hists, HISTC_GLOBAL_WEIGHT, 12); - if (h->srcline) - hists__new_col_len(hists, HISTC_SRCLINE, strlen(h->srcline)); + if (h->srcline) { + len = MAX(strlen(h->srcline), strlen(sort_srcline.se_header)); + hists__new_col_len(hists, HISTC_SRCLINE, len); + } if (h->srcfile) hists__new_col_len(hists, HISTC_SRCFILE, strlen(h->srcfile)); @@ -417,6 +419,8 @@ static int hist_entry__init(struct hist_entry *he, } INIT_LIST_HEAD(&he->pairs.node); thread__get(he->thread); + he->hroot_in = RB_ROOT; + he->hroot_out = RB_ROOT; if (!symbol_conf.report_hierarchy) he->leaf = true; @@ -2149,6 +2153,50 @@ out: return he; } +static struct hist_entry *add_dummy_hierarchy_entry(struct hists *hists, + struct rb_root *root, + struct hist_entry *pair) +{ + struct rb_node **p; + struct rb_node *parent = NULL; + struct hist_entry *he; + struct perf_hpp_fmt *fmt; + + p = &root->rb_node; + while (*p != NULL) { + int64_t cmp = 0; + + parent = *p; + he = rb_entry(parent, struct hist_entry, rb_node_in); + + perf_hpp_list__for_each_sort_list(he->hpp_list, fmt) { + cmp = fmt->collapse(fmt, he, pair); + if (cmp) + break; + } + if (!cmp) + goto out; + + if (cmp < 0) + p = &parent->rb_left; + else + p = &parent->rb_right; + } + + he = hist_entry__new(pair, true); + if (he) { + rb_link_node(&he->rb_node_in, parent, p); + rb_insert_color(&he->rb_node_in, root); + + he->dummy = true; + he->hists = hists; + memset(&he->stat, 0, sizeof(he->stat)); + hists__inc_stats(hists, he); + } +out: + return he; +} + static struct hist_entry *hists__find_entry(struct hists *hists, struct hist_entry *he) { @@ -2174,6 +2222,51 @@ static struct hist_entry *hists__find_entry(struct hists *hists, return NULL; } +static struct hist_entry *hists__find_hierarchy_entry(struct rb_root *root, + struct hist_entry *he) +{ + struct rb_node *n = root->rb_node; + + while (n) { + struct hist_entry *iter; + struct perf_hpp_fmt *fmt; + int64_t cmp = 0; + + iter = rb_entry(n, struct hist_entry, rb_node_in); + perf_hpp_list__for_each_sort_list(he->hpp_list, fmt) { + cmp = fmt->collapse(fmt, iter, he); + if (cmp) + break; + } + + if (cmp < 0) + n = n->rb_left; + else if (cmp > 0) + n = n->rb_right; + else + return iter; + } + + return NULL; +} + +static void hists__match_hierarchy(struct rb_root *leader_root, + struct rb_root *other_root) +{ + struct rb_node *nd; + struct hist_entry *pos, *pair; + + for (nd = rb_first(leader_root); nd; nd = rb_next(nd)) { + pos = rb_entry(nd, struct hist_entry, rb_node_in); + pair = hists__find_hierarchy_entry(other_root, pos); + + if (pair) { + hist_entry__add_pair(pair, pos); + hists__match_hierarchy(&pos->hroot_in, &pair->hroot_in); + } + } +} + /* * Look for pairs to link to the leader buckets (hist_entries): */ @@ -2183,6 +2276,12 @@ void hists__match(struct hists *leader, struct hists *other) struct rb_node *nd; struct hist_entry *pos, *pair; + if (symbol_conf.report_hierarchy) { + /* hierarchy report always collapses entries */ + return hists__match_hierarchy(&leader->entries_collapsed, + &other->entries_collapsed); + } + if (hists__has(leader, need_collapse)) root = &leader->entries_collapsed; else @@ -2197,6 +2296,50 @@ void hists__match(struct hists *leader, struct hists *other) } } +static int hists__link_hierarchy(struct hists *leader_hists, + struct hist_entry *parent, + struct rb_root *leader_root, + struct rb_root *other_root) +{ + struct rb_node *nd; + struct hist_entry *pos, *leader; + + for (nd = rb_first(other_root); nd; nd = rb_next(nd)) { + pos = rb_entry(nd, struct hist_entry, rb_node_in); + + if (hist_entry__has_pairs(pos)) { + bool found = false; + + list_for_each_entry(leader, &pos->pairs.head, pairs.node) { + if (leader->hists == leader_hists) { + found = true; + break; + } + } + if (!found) + return -1; + } else { + leader = add_dummy_hierarchy_entry(leader_hists, + leader_root, pos); + if (leader == NULL) + return -1; + + /* do not point parent in the pos */ + leader->parent_he = parent; + + hist_entry__add_pair(pos, leader); + } + + if (!pos->leaf) { + if (hists__link_hierarchy(leader_hists, leader, + &leader->hroot_in, + &pos->hroot_in) < 0) + return -1; + } + } + return 0; +} + /* * Look for entries in the other hists that are not present in the leader, if * we find them, just add a dummy entry on the leader hists, with period=0, @@ -2208,6 +2351,13 @@ int hists__link(struct hists *leader, struct hists *other) struct rb_node *nd; struct hist_entry *pos, *pair; + if (symbol_conf.report_hierarchy) { + /* hierarchy report always collapses entries */ + return hists__link_hierarchy(leader, NULL, + &leader->entries_collapsed, + &other->entries_collapsed); + } + if (hists__has(other, need_collapse)) root = &other->entries_collapsed; else diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 0a1edf1ab450..defa957f27df 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -230,7 +230,7 @@ struct perf_hpp { struct perf_hpp_fmt { const char *name; int (*header)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, - struct hists *hists); + struct hists *hists, int line, int *span); int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hists *hists); int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, @@ -259,6 +259,7 @@ struct perf_hpp_list { struct list_head fields; struct list_head sorts; + int nr_header_lines; int need_collapse; int parent; int sym; @@ -367,6 +368,7 @@ static inline bool perf_hpp__should_skip(struct perf_hpp_fmt *format, void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists); void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists); void perf_hpp__set_user_width(const char *width_list_str); +void hists__reset_column_width(struct hists *hists); typedef u64 (*hpp_field_fn)(struct hist_entry *he); typedef int (*hpp_callback_fn)(struct perf_hpp *hpp, bool front); diff --git a/tools/perf/util/include/dwarf-regs.h b/tools/perf/util/include/dwarf-regs.h index 07c644ed64c4..43bfd8da7919 100644 --- a/tools/perf/util/include/dwarf-regs.h +++ b/tools/perf/util/include/dwarf-regs.h @@ -3,6 +3,12 @@ #ifdef HAVE_DWARF_SUPPORT const char *get_arch_regstr(unsigned int n); +/* + * get_dwarf_regstr - Returns ftrace register string from DWARF regnum + * n: DWARF register number + * machine: ELF machine signature (EM_*) + */ +const char *get_dwarf_regstr(unsigned int n, unsigned int machine); #endif #ifdef HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET diff --git a/tools/perf/util/intel-bts.c b/tools/perf/util/intel-bts.c index 749e6f2e37ca..f545ec1e758a 100644 --- a/tools/perf/util/intel-bts.c +++ b/tools/perf/util/intel-bts.c @@ -346,7 +346,7 @@ static int intel_bts_get_next_insn(struct intel_bts_queue *btsq, u64 ip) goto out_put; /* Load maps to ensure dso->is_64_bit has been updated */ - map__load(al.map, machine->symbol_filter); + map__load(al.map); x86_64 = al.map->dso->is_64_bit; diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 551ff6f640be..b9cc353cace2 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -477,7 +477,7 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn, start_ip = *ip; /* Load maps to ensure dso->is_64_bit has been updated */ - map__load(al.map, machine->symbol_filter); + map__load(al.map); x86_64 = al.map->dso->is_64_bit; @@ -1294,7 +1294,7 @@ static u64 intel_pt_switch_ip(struct intel_pt *pt, u64 *ptss_ip) if (!map) return 0; - if (map__load(map, machine->symbol_filter)) + if (map__load(map)) return 0; start = dso__first_symbol(map->dso, MAP__FUNCTION); diff --git a/tools/perf/util/lzma.c b/tools/perf/util/lzma.c index 95a1acb61245..9ddea5cecd94 100644 --- a/tools/perf/util/lzma.c +++ b/tools/perf/util/lzma.c @@ -29,6 +29,7 @@ int lzma_decompress_to_file(const char *input, int output_fd) lzma_action action = LZMA_RUN; lzma_stream strm = LZMA_STREAM_INIT; lzma_ret ret; + int err = -1; u8 buf_in[BUFSIZE]; u8 buf_out[BUFSIZE]; @@ -45,7 +46,7 @@ int lzma_decompress_to_file(const char *input, int output_fd) if (ret != LZMA_OK) { pr_err("lzma: lzma_stream_decoder failed %s (%d)\n", lzma_strerror(ret), ret); - return -1; + goto err_fclose; } strm.next_in = NULL; @@ -60,7 +61,7 @@ int lzma_decompress_to_file(const char *input, int output_fd) if (ferror(infile)) { pr_err("lzma: read error: %s\n", strerror(errno)); - return -1; + goto err_fclose; } if (feof(infile)) @@ -74,7 +75,7 @@ int lzma_decompress_to_file(const char *input, int output_fd) if (writen(output_fd, buf_out, write_size) != write_size) { pr_err("lzma: write error: %s\n", strerror(errno)); - return -1; + goto err_fclose; } strm.next_out = buf_out; @@ -83,13 +84,15 @@ int lzma_decompress_to_file(const char *input, int output_fd) if (ret != LZMA_OK) { if (ret == LZMA_STREAM_END) - return 0; + break; pr_err("lzma: failed %s\n", lzma_strerror(ret)); - return -1; + goto err_fclose; } } + err = 0; +err_fclose: fclose(infile); - return 0; + return err; } diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index cb6388dbdd98..18e4519abef2 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -41,7 +41,6 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid) machine->pid = pid; - machine->symbol_filter = NULL; machine->id_hdr_size = 0; machine->kptr_restrict_warned = false; machine->comm_exec = false; @@ -148,7 +147,6 @@ void machines__init(struct machines *machines) { machine__init(&machines->host, "", HOST_KERNEL_ID); machines->guests = RB_ROOT; - machines->symbol_filter = NULL; } void machines__exit(struct machines *machines) @@ -172,8 +170,6 @@ struct machine *machines__add(struct machines *machines, pid_t pid, return NULL; } - machine->symbol_filter = machines->symbol_filter; - while (*p != NULL) { parent = *p; pos = rb_entry(parent, struct machine, rb_node); @@ -189,21 +185,6 @@ struct machine *machines__add(struct machines *machines, pid_t pid, return machine; } -void machines__set_symbol_filter(struct machines *machines, - symbol_filter_t symbol_filter) -{ - struct rb_node *nd; - - machines->symbol_filter = symbol_filter; - machines->host.symbol_filter = symbol_filter; - - for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { - struct machine *machine = rb_entry(nd, struct machine, rb_node); - - machine->symbol_filter = symbol_filter; - } -} - void machines__set_comm_exec(struct machines *machines, bool comm_exec) { struct rb_node *nd; @@ -916,10 +897,10 @@ int machines__create_kernel_maps(struct machines *machines, pid_t pid) } int __machine__load_kallsyms(struct machine *machine, const char *filename, - enum map_type type, bool no_kcore, symbol_filter_t filter) + enum map_type type, bool no_kcore) { struct map *map = machine__kernel_map(machine); - int ret = __dso__load_kallsyms(map->dso, filename, map, no_kcore, filter); + int ret = __dso__load_kallsyms(map->dso, filename, map, no_kcore); if (ret > 0) { dso__set_loaded(map->dso, type); @@ -935,16 +916,15 @@ int __machine__load_kallsyms(struct machine *machine, const char *filename, } int machine__load_kallsyms(struct machine *machine, const char *filename, - enum map_type type, symbol_filter_t filter) + enum map_type type) { - return __machine__load_kallsyms(machine, filename, type, false, filter); + return __machine__load_kallsyms(machine, filename, type, false); } -int machine__load_vmlinux_path(struct machine *machine, enum map_type type, - symbol_filter_t filter) +int machine__load_vmlinux_path(struct machine *machine, enum map_type type) { struct map *map = machine__kernel_map(machine); - int ret = dso__load_vmlinux_path(map->dso, map, filter); + int ret = dso__load_vmlinux_path(map->dso, map); if (ret > 0) dso__set_loaded(map->dso, type); @@ -1313,7 +1293,7 @@ static int machine__process_kernel_mmap_event(struct machine *machine, /* * preload dso of guest kernel and modules */ - dso__load(kernel, machine__kernel_map(machine), NULL); + dso__load(kernel, machine__kernel_map(machine)); } } return 0; @@ -2115,7 +2095,7 @@ int machine__get_kernel_start(struct machine *machine) */ machine->kernel_start = 1ULL << 63; if (map) { - err = map__load(map, machine->symbol_filter); + err = map__load(map); if (map->start) machine->kernel_start = map->start; } @@ -2131,7 +2111,7 @@ char *machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, ch { struct machine *machine = vmachine; struct map *map; - struct symbol *sym = map_groups__find_symbol(&machine->kmaps, MAP__FUNCTION, *addrp, &map, NULL); + struct symbol *sym = map_groups__find_symbol(&machine->kmaps, MAP__FUNCTION, *addrp, &map); if (sym == NULL) return NULL; diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index 20739f746bc4..354de6e56109 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h @@ -41,7 +41,6 @@ struct machine { struct map_groups kmaps; struct map *vmlinux_maps[MAP__NR_TYPES]; u64 kernel_start; - symbol_filter_t symbol_filter; pid_t *current_tid; union { /* Tool specific area */ void *priv; @@ -110,7 +109,6 @@ typedef void (*machine__process_t)(struct machine *machine, void *data); struct machines { struct machine host; struct rb_root guests; - symbol_filter_t symbol_filter; }; void machines__init(struct machines *machines); @@ -128,8 +126,6 @@ struct machine *machines__findnew(struct machines *machines, pid_t pid); void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size); char *machine__mmap_name(struct machine *machine, char *bf, size_t size); -void machines__set_symbol_filter(struct machines *machines, - symbol_filter_t symbol_filter); void machines__set_comm_exec(struct machines *machines, bool comm_exec); struct machine *machine__new_host(void); @@ -178,40 +174,33 @@ size_t machine__fprintf(struct machine *machine, FILE *fp); static inline struct symbol *machine__find_kernel_symbol(struct machine *machine, enum map_type type, u64 addr, - struct map **mapp, - symbol_filter_t filter) + struct map **mapp) { - return map_groups__find_symbol(&machine->kmaps, type, addr, - mapp, filter); + return map_groups__find_symbol(&machine->kmaps, type, addr, mapp); } static inline struct symbol *machine__find_kernel_symbol_by_name(struct machine *machine, enum map_type type, const char *name, - struct map **mapp, - symbol_filter_t filter) + struct map **mapp) { - return map_groups__find_symbol_by_name(&machine->kmaps, type, name, - mapp, filter); + return map_groups__find_symbol_by_name(&machine->kmaps, type, name, mapp); } static inline struct symbol *machine__find_kernel_function(struct machine *machine, u64 addr, - struct map **mapp, - symbol_filter_t filter) + struct map **mapp) { return machine__find_kernel_symbol(machine, MAP__FUNCTION, addr, - mapp, filter); + mapp); } static inline struct symbol *machine__find_kernel_function_by_name(struct machine *machine, const char *name, - struct map **mapp, - symbol_filter_t filter) + struct map **mapp) { - return map_groups__find_function_by_name(&machine->kmaps, name, mapp, - filter); + return map_groups__find_function_by_name(&machine->kmaps, name, mapp); } struct map *machine__findnew_module_map(struct machine *machine, u64 start, @@ -219,11 +208,10 @@ struct map *machine__findnew_module_map(struct machine *machine, u64 start, int arch__fix_module_text_start(u64 *start, const char *name); int __machine__load_kallsyms(struct machine *machine, const char *filename, - enum map_type type, bool no_kcore, symbol_filter_t filter); + enum map_type type, bool no_kcore); int machine__load_kallsyms(struct machine *machine, const char *filename, - enum map_type type, symbol_filter_t filter); -int machine__load_vmlinux_path(struct machine *machine, enum map_type type, - symbol_filter_t filter); + enum map_type type); +int machine__load_vmlinux_path(struct machine *machine, enum map_type type); size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, bool (skip)(struct dso *dso, int parm), int parm); diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 728129ac653a..c662fef95d14 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -6,6 +6,7 @@ #include <string.h> #include <stdio.h> #include <unistd.h> +#include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */ #include "map.h" #include "thread.h" #include "strlist.h" @@ -24,9 +25,10 @@ const char *map_type__name[MAP__NR_TYPES] = { [MAP__VARIABLE] = "Variables", }; -static inline int is_anon_memory(const char *filename) +static inline int is_anon_memory(const char *filename, u32 flags) { - return !strcmp(filename, "//anon") || + return flags & MAP_HUGETLB || + !strcmp(filename, "//anon") || !strncmp(filename, "/dev/zero", sizeof("/dev/zero") - 1) || !strncmp(filename, "/anon_hugepage", sizeof("/anon_hugepage") - 1); } @@ -155,7 +157,7 @@ struct map *map__new(struct machine *machine, u64 start, u64 len, int anon, no_dso, vdso, android; android = is_android_lib(filename); - anon = is_anon_memory(filename); + anon = is_anon_memory(filename, flags); vdso = is_vdso_map(filename); no_dso = is_no_dso_memory(filename); @@ -279,7 +281,7 @@ void map__fixup_end(struct map *map) #define DSO__DELETED "(deleted)" -int map__load(struct map *map, symbol_filter_t filter) +int map__load(struct map *map) { const char *name = map->dso->long_name; int nr; @@ -287,7 +289,7 @@ int map__load(struct map *map, symbol_filter_t filter) if (dso__loaded(map->dso, map->type)) return 0; - nr = dso__load(map->dso, map, filter); + nr = dso__load(map->dso, map); if (nr < 0) { if (map->dso->has_build_id) { char sbuild_id[SBUILD_ID_SIZE]; @@ -312,9 +314,6 @@ int map__load(struct map *map, symbol_filter_t filter) pr_warning("%.*s was updated (is prelink enabled?). " "Restart the long running apps that use it!\n", (int)real_len, name); - } else if (filter) { - pr_warning("no symbols passed the given filter.\n"); - return -2; /* Empty but maybe by the filter */ } else { pr_warning("no symbols found in %s, maybe install " "a debug package?\n", name); @@ -331,19 +330,17 @@ int __weak arch__compare_symbol_names(const char *namea, const char *nameb) return strcmp(namea, nameb); } -struct symbol *map__find_symbol(struct map *map, u64 addr, - symbol_filter_t filter) +struct symbol *map__find_symbol(struct map *map, u64 addr) { - if (map__load(map, filter) < 0) + if (map__load(map) < 0) return NULL; return dso__find_symbol(map->dso, map->type, addr); } -struct symbol *map__find_symbol_by_name(struct map *map, const char *name, - symbol_filter_t filter) +struct symbol *map__find_symbol_by_name(struct map *map, const char *name) { - if (map__load(map, filter) < 0) + if (map__load(map) < 0) return NULL; if (!dso__sorted_by_name(map->dso, map->type)) @@ -556,23 +553,22 @@ void map_groups__put(struct map_groups *mg) struct symbol *map_groups__find_symbol(struct map_groups *mg, enum map_type type, u64 addr, - struct map **mapp, - symbol_filter_t filter) + struct map **mapp) { struct map *map = map_groups__find(mg, type, addr); /* Ensure map is loaded before using map->map_ip */ - if (map != NULL && map__load(map, filter) >= 0) { + if (map != NULL && map__load(map) >= 0) { if (mapp != NULL) *mapp = map; - return map__find_symbol(map, map->map_ip(map, addr), filter); + return map__find_symbol(map, map->map_ip(map, addr)); } return NULL; } struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, - struct map **mapp, symbol_filter_t filter) + struct map **mapp) { struct symbol *sym; struct rb_node *nd; @@ -582,7 +578,7 @@ struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, for (nd = rb_first(&maps->entries); nd; nd = rb_next(nd)) { struct map *pos = rb_entry(nd, struct map, rb_node); - sym = map__find_symbol_by_name(pos, name, filter); + sym = map__find_symbol_by_name(pos, name); if (sym == NULL) continue; @@ -600,15 +596,14 @@ out: struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg, enum map_type type, const char *name, - struct map **mapp, - symbol_filter_t filter) + struct map **mapp) { - struct symbol *sym = maps__find_symbol_by_name(&mg->maps[type], name, mapp, filter); + struct symbol *sym = maps__find_symbol_by_name(&mg->maps[type], name, mapp); return sym; } -int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter) +int map_groups__find_ams(struct addr_map_symbol *ams) { if (ams->addr < ams->map->start || ams->addr >= ams->map->end) { if (ams->map->groups == NULL) @@ -620,7 +615,7 @@ int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter) } ams->al_addr = ams->map->map_ip(ams->map, ams->addr); - ams->sym = map__find_symbol(ams->map, ams->al_addr, filter); + ams->sym = map__find_symbol(ams->map, ams->al_addr); return ams->sym ? 0 : -1; } diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index d83396ceecba..abdacf800c98 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -127,17 +127,14 @@ struct thread; * @map: the 'struct map *' in which symbols itereated * @sym_name: the symbol name * @pos: the 'struct symbol *' to use as a loop cursor - * @filter: to use when loading the DSO */ -#define __map__for_each_symbol_by_name(map, sym_name, pos, filter) \ - for (pos = map__find_symbol_by_name(map, sym_name, filter); \ +#define __map__for_each_symbol_by_name(map, sym_name, pos) \ + for (pos = map__find_symbol_by_name(map, sym_name); \ pos && arch__compare_symbol_names(pos->name, sym_name) == 0; \ pos = symbol__next_by_name(pos)) #define map__for_each_symbol_by_name(map, sym_name, pos) \ - __map__for_each_symbol_by_name(map, sym_name, (pos), NULL) - -typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); + __map__for_each_symbol_by_name(map, sym_name, (pos)) int arch__compare_symbol_names(const char *namea, const char *nameb); void map__init(struct map *map, enum map_type type, @@ -173,11 +170,9 @@ size_t map__fprintf_dsoname(struct map *map, FILE *fp); int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix, FILE *fp); -int map__load(struct map *map, symbol_filter_t filter); -struct symbol *map__find_symbol(struct map *map, - u64 addr, symbol_filter_t filter); -struct symbol *map__find_symbol_by_name(struct map *map, const char *name, - symbol_filter_t filter); +int map__load(struct map *map); +struct symbol *map__find_symbol(struct map *map, u64 addr); +struct symbol *map__find_symbol_by_name(struct map *map, const char *name); void map__fixup_start(struct map *map); void map__fixup_end(struct map *map); @@ -191,7 +186,7 @@ struct map *maps__find(struct maps *maps, u64 addr); struct map *maps__first(struct maps *maps); struct map *map__next(struct map *map); struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, - struct map **mapp, symbol_filter_t filter); + struct map **mapp); void map_groups__init(struct map_groups *mg, struct machine *machine); void map_groups__exit(struct map_groups *mg); int map_groups__clone(struct thread *thread, @@ -231,25 +226,22 @@ static inline struct map *map_groups__next(struct map *map) struct symbol *map_groups__find_symbol(struct map_groups *mg, enum map_type type, u64 addr, - struct map **mapp, - symbol_filter_t filter); + struct map **mapp); struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg, enum map_type type, const char *name, - struct map **mapp, - symbol_filter_t filter); + struct map **mapp); struct addr_map_symbol; -int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter); +int map_groups__find_ams(struct addr_map_symbol *ams); static inline struct symbol *map_groups__find_function_by_name(struct map_groups *mg, - const char *name, struct map **mapp, - symbol_filter_t filter) + const char *name, struct map **mapp) { - return map_groups__find_symbol_by_name(mg, MAP__FUNCTION, name, mapp, filter); + return map_groups__find_symbol_by_name(mg, MAP__FUNCTION, name, mapp); } int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 6c913c3914fb..2eb8b1ed4cc8 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -904,6 +904,7 @@ static const char *config_term_names[__PARSE_EVENTS__TERM_TYPE_NR] = { [PARSE_EVENTS__TERM_TYPE_MAX_STACK] = "max-stack", [PARSE_EVENTS__TERM_TYPE_OVERWRITE] = "overwrite", [PARSE_EVENTS__TERM_TYPE_NOOVERWRITE] = "no-overwrite", + [PARSE_EVENTS__TERM_TYPE_DRV_CFG] = "driver-config", }; static bool config_term_shrinked; @@ -1034,7 +1035,8 @@ static int config_term_pmu(struct perf_event_attr *attr, struct parse_events_term *term, struct parse_events_error *err) { - if (term->type_term == PARSE_EVENTS__TERM_TYPE_USER) + if (term->type_term == PARSE_EVENTS__TERM_TYPE_USER || + term->type_term == PARSE_EVENTS__TERM_TYPE_DRV_CFG) /* * Always succeed for sysfs terms, as we dont know * at this point what type they need to have. @@ -1134,6 +1136,9 @@ do { \ case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE: ADD_CONFIG_TERM(OVERWRITE, overwrite, term->val.num ? 0 : 1); break; + case PARSE_EVENTS__TERM_TYPE_DRV_CFG: + ADD_CONFIG_TERM(DRV_CFG, drv_cfg, term->val.str); + break; default: break; } diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index d1edbf8cc66a..8d09a976fca8 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -71,6 +71,7 @@ enum { PARSE_EVENTS__TERM_TYPE_MAX_STACK, PARSE_EVENTS__TERM_TYPE_NOOVERWRITE, PARSE_EVENTS__TERM_TYPE_OVERWRITE, + PARSE_EVENTS__TERM_TYPE_DRV_CFG, __PARSE_EVENTS__TERM_TYPE_NR, }; diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 7a2519435da0..9f43fda2570f 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -53,6 +53,26 @@ static int str(yyscan_t scanner, int token) return token; } +/* + * This function is called when the parser gets two kind of input: + * + * @cfg1 or @cfg2=config + * + * The leading '@' is stripped off before 'cfg1' and 'cfg2=config' are given to + * bison. In the latter case it is necessary to keep the string intact so that + * the PMU kernel driver can determine what configurable is associated to + * 'config'. + */ +static int drv_str(yyscan_t scanner, int token) +{ + YYSTYPE *yylval = parse_events_get_lval(scanner); + char *text = parse_events_get_text(scanner); + + /* Strip off the '@' */ + yylval->str = strdup(text + 1); + return token; +} + #define REWIND(__alloc) \ do { \ YYSTYPE *__yylval = parse_events_get_lval(yyscanner); \ @@ -124,6 +144,7 @@ num_hex 0x[a-fA-F0-9]+ num_raw_hex [a-fA-F0-9]+ name [a-zA-Z_*?][a-zA-Z0-9_*?.]* name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?.:]* +drv_cfg_term [a-zA-Z0-9_\.]+(=[a-zA-Z0-9_*?\.:]+)? /* If you add a modifier you need to update check_modifier() */ modifier_event [ukhpPGHSDI]+ modifier_bp [rwx]{1,3} @@ -209,6 +230,7 @@ no-overwrite { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOOVERWRITE); } {name_minus} { return str(yyscanner, PE_NAME); } \[all\] { return PE_ARRAY_ALL; } "[" { BEGIN(array); return '['; } +@{drv_cfg_term} { return drv_str(yyscanner, PE_DRV_CFG_TERM); } } <mem>{ diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 5be4a5f216d6..879115f93edc 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -49,6 +49,7 @@ static void inc_group_count(struct list_head *list, %token PE_ERROR %token PE_PMU_EVENT_PRE PE_PMU_EVENT_SUF PE_KERNEL_PMU_EVENT %token PE_ARRAY_ALL PE_ARRAY_RANGE +%token PE_DRV_CFG_TERM %type <num> PE_VALUE %type <num> PE_VALUE_SYM_HW %type <num> PE_VALUE_SYM_SW @@ -63,6 +64,7 @@ static void inc_group_count(struct list_head *list, %type <str> PE_MODIFIER_BP %type <str> PE_EVENT_NAME %type <str> PE_PMU_EVENT_PRE PE_PMU_EVENT_SUF PE_KERNEL_PMU_EVENT +%type <str> PE_DRV_CFG_TERM %type <num> value_sym %type <head> event_config %type <head> opt_event_config @@ -599,6 +601,15 @@ PE_NAME array '=' PE_VALUE term->array = $2; $$ = term; } +| +PE_DRV_CFG_TERM +{ + struct parse_events_term *term; + + ABORT_ON(parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_DRV_CFG, + $1, $1, &@1, NULL)); + $$ = term; +} array: '[' array_terms ']' diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index ddb0261b2577..2babcdf62839 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -445,14 +445,23 @@ static struct cpu_map *pmu_cpumask(const char *name) FILE *file; struct cpu_map *cpus; const char *sysfs = sysfs__mountpoint(); + const char *templates[] = { + "%s/bus/event_source/devices/%s/cpumask", + "%s/bus/event_source/devices/%s/cpus", + NULL + }; + const char **template; if (!sysfs) return NULL; - snprintf(path, PATH_MAX, - "%s/bus/event_source/devices/%s/cpumask", sysfs, name); + for (template = templates; *template; template++) { + snprintf(path, PATH_MAX, *template, sysfs, name); + if (stat(path, &st) == 0) + break; + } - if (stat(path, &st) < 0) + if (!*template) return NULL; file = fopen(path, "r"); diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 28733962cd80..bc60ce49720b 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -110,13 +110,12 @@ void exit_probe_symbol_maps(void) static struct symbol *__find_kernel_function_by_name(const char *name, struct map **mapp) { - return machine__find_kernel_function_by_name(host_machine, name, mapp, - NULL); + return machine__find_kernel_function_by_name(host_machine, name, mapp); } static struct symbol *__find_kernel_function(u64 addr, struct map **mapp) { - return machine__find_kernel_function(host_machine, addr, mapp, NULL); + return machine__find_kernel_function(host_machine, addr, mapp); } static struct ref_reloc_sym *kernel_get_ref_reloc_sym(void) @@ -125,7 +124,7 @@ static struct ref_reloc_sym *kernel_get_ref_reloc_sym(void) struct kmap *kmap; struct map *map = machine__kernel_map(host_machine); - if (map__load(map, NULL) < 0) + if (map__load(map) < 0) return NULL; kmap = map__kmap(map); @@ -351,9 +350,9 @@ static int kernel_get_module_dso(const char *module, struct dso **pdso) vmlinux_name = symbol_conf.vmlinux_name; dso->load_errno = 0; if (vmlinux_name) - ret = dso__load_vmlinux(dso, map, vmlinux_name, false, NULL); + ret = dso__load_vmlinux(dso, map, vmlinux_name, false); else - ret = dso__load_vmlinux_path(dso, map, NULL); + ret = dso__load_vmlinux_path(dso, map); found: *pdso = dso; return ret; @@ -674,6 +673,10 @@ post_process_kernel_probe_trace_events(struct probe_trace_event *tevs, char *tmp; int i, skipped = 0; + /* Skip post process if the target is an offline kernel */ + if (symbol_conf.ignore_vmlinux_buildid) + return 0; + reloc_sym = kernel_get_ref_reloc_sym(); if (!reloc_sym) { pr_warning("Relocated base symbol is not found!\n"); @@ -1614,19 +1617,27 @@ out: return ret; } +/* Returns true if *any* ARG is either C variable, $params or $vars. */ +bool perf_probe_with_var(struct perf_probe_event *pev) +{ + int i = 0; + + for (i = 0; i < pev->nargs; i++) + if (is_c_varname(pev->args[i].var) || + !strcmp(pev->args[i].var, PROBE_ARG_PARAMS) || + !strcmp(pev->args[i].var, PROBE_ARG_VARS)) + return true; + return false; +} + /* Return true if this perf_probe_event requires debuginfo */ bool perf_probe_event_need_dwarf(struct perf_probe_event *pev) { - int i; - if (pev->point.file || pev->point.line || pev->point.lazy_line) return true; - for (i = 0; i < pev->nargs; i++) - if (is_c_varname(pev->args[i].var) || - !strcmp(pev->args[i].var, "$params") || - !strcmp(pev->args[i].var, "$vars")) - return true; + if (perf_probe_with_var(pev)) + return true; return false; } @@ -1987,7 +1998,7 @@ static int find_perf_probe_point_from_map(struct probe_trace_point *tp, map = dso__new_map(tp->module); if (!map) goto out; - sym = map__find_symbol(map, addr, NULL); + sym = map__find_symbol(map, addr); } else { if (tp->symbol && !addr) { if (kernel_get_symbol_address_by_name(tp->symbol, @@ -2692,7 +2703,7 @@ static int find_probe_functions(struct map *map, char *name, struct symbol *sym; struct rb_node *tmp; - if (map__load(map, NULL) < 0) + if (map__load(map) < 0) return 0; map__for_each_symbol(map, sym, tmp) { @@ -3207,6 +3218,52 @@ int convert_perf_probe_events(struct perf_probe_event *pevs, int npevs) return 0; } +static int show_probe_trace_event(struct probe_trace_event *tev) +{ + char *buf = synthesize_probe_trace_command(tev); + + if (!buf) { + pr_debug("Failed to synthesize probe trace event.\n"); + return -EINVAL; + } + + /* Showing definition always go stdout */ + printf("%s\n", buf); + free(buf); + + return 0; +} + +int show_probe_trace_events(struct perf_probe_event *pevs, int npevs) +{ + struct strlist *namelist = strlist__new(NULL, NULL); + struct probe_trace_event *tev; + struct perf_probe_event *pev; + int i, j, ret = 0; + + if (!namelist) + return -ENOMEM; + + for (j = 0; j < npevs && !ret; j++) { + pev = &pevs[j]; + for (i = 0; i < pev->ntevs && !ret; i++) { + tev = &pev->tevs[i]; + /* Skip if the symbol is out of .text or blacklisted */ + if (!tev->point.symbol && !pev->uprobes) + continue; + + /* Set new name for tev (and update namelist) */ + ret = probe_trace_event__set_name(tev, pev, + namelist, true); + if (!ret) + ret = show_probe_trace_event(tev); + } + } + strlist__delete(namelist); + + return ret; +} + int apply_perf_probe_events(struct perf_probe_event *pevs, int npevs) { int i, ret = 0; @@ -3289,24 +3346,10 @@ out: return ret; } -/* TODO: don't use a global variable for filter ... */ -static struct strfilter *available_func_filter; - -/* - * If a symbol corresponds to a function with global binding and - * matches filter return 0. For all others return 1. - */ -static int filter_available_functions(struct map *map __maybe_unused, - struct symbol *sym) -{ - if (strfilter__compare(available_func_filter, sym->name)) - return 0; - return 1; -} - int show_available_funcs(const char *target, struct strfilter *_filter, bool user) { + struct rb_node *nd; struct map *map; int ret; @@ -3324,9 +3367,7 @@ int show_available_funcs(const char *target, struct strfilter *_filter, return -EINVAL; } - /* Load symbols with given filter */ - available_func_filter = _filter; - ret = map__load(map, filter_available_functions); + ret = map__load(map); if (ret) { if (ret == -2) { char *str = strfilter__string(_filter); @@ -3343,7 +3384,14 @@ int show_available_funcs(const char *target, struct strfilter *_filter, /* Show all (filtered) symbols */ setup_pager(); - dso__fprintf_symbols_by_name(map->dso, map->type, stdout); + + for (nd = rb_first(&map->dso->symbol_names[map->type]); nd; nd = rb_next(nd)) { + struct symbol_name_rb_node *pos = rb_entry(nd, struct symbol_name_rb_node, rb_node); + + if (strfilter__compare(_filter, pos->sym.name)) + printf("%s\n", pos->sym.name); + } + end: if (user) { map__put(map); diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index f4f45db77c1c..8091d15113f7 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h @@ -128,6 +128,8 @@ char *synthesize_perf_probe_point(struct perf_probe_point *pp); int perf_probe_event__copy(struct perf_probe_event *dst, struct perf_probe_event *src); +bool perf_probe_with_var(struct perf_probe_event *pev); + /* Check the perf_probe_event needs debuginfo */ bool perf_probe_event_need_dwarf(struct perf_probe_event *pev); @@ -147,6 +149,7 @@ int line_range__init(struct line_range *lr); int add_perf_probe_events(struct perf_probe_event *pevs, int npevs); int convert_perf_probe_events(struct perf_probe_event *pevs, int npevs); int apply_perf_probe_events(struct perf_probe_event *pevs, int npevs); +int show_probe_trace_events(struct perf_probe_event *pevs, int npevs); void cleanup_perf_probe_events(struct perf_probe_event *pevs, int npevs); int del_perf_probe_events(struct strfilter *filter); diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index 9c3b9ed5b3c3..6f931e442f14 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -73,11 +73,10 @@ static void print_both_open_warning(int kerr, int uerr) static int open_probe_events(const char *trace_file, bool readwrite) { char buf[PATH_MAX]; - const char *tracing_dir = ""; int ret; - ret = e_snprintf(buf, PATH_MAX, "%s/%s%s", - tracing_path, tracing_dir, trace_file); + ret = e_snprintf(buf, PATH_MAX, "%s/%s", + tracing_path, trace_file); if (ret >= 0) { pr_debug("Opening %s write=%d\n", buf, readwrite); if (readwrite && !probe_event_dry_run) @@ -877,3 +876,60 @@ int probe_cache__show_all_caches(struct strfilter *filter) return 0; } + +static struct { + const char *pattern; + bool avail; + bool checked; +} probe_type_table[] = { +#define DEFINE_TYPE(idx, pat, def_avail) \ + [idx] = {.pattern = pat, .avail = (def_avail)} + DEFINE_TYPE(PROBE_TYPE_U, "* u8/16/32/64,*", true), + DEFINE_TYPE(PROBE_TYPE_S, "* s8/16/32/64,*", true), + DEFINE_TYPE(PROBE_TYPE_X, "* x8/16/32/64,*", false), + DEFINE_TYPE(PROBE_TYPE_STRING, "* string,*", true), + DEFINE_TYPE(PROBE_TYPE_BITFIELD, + "* b<bit-width>@<bit-offset>/<container-size>", true), +}; + +bool probe_type_is_available(enum probe_type type) +{ + FILE *fp; + char *buf = NULL; + size_t len = 0; + bool target_line = false; + bool ret = probe_type_table[type].avail; + + if (type >= PROBE_TYPE_END) + return false; + /* We don't have to check the type which supported by default */ + if (ret || probe_type_table[type].checked) + return ret; + + if (asprintf(&buf, "%s/README", tracing_path) < 0) + return ret; + + fp = fopen(buf, "r"); + if (!fp) + goto end; + + zfree(&buf); + while (getline(&buf, &len, fp) > 0 && !ret) { + if (!target_line) { + target_line = !!strstr(buf, " type: "); + if (!target_line) + continue; + } else if (strstr(buf, "\t ") != buf) + break; + ret = strglobmatch(buf, probe_type_table[type].pattern); + } + /* Cache the result */ + probe_type_table[type].checked = true; + probe_type_table[type].avail = ret; + + fclose(fp); +end: + free(buf); + + return ret; +} diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h index 9577b5c0b487..eba44c3e9dca 100644 --- a/tools/perf/util/probe-file.h +++ b/tools/perf/util/probe-file.h @@ -19,6 +19,15 @@ struct probe_cache { struct list_head entries; }; +enum probe_type { + PROBE_TYPE_U = 0, + PROBE_TYPE_S, + PROBE_TYPE_X, + PROBE_TYPE_STRING, + PROBE_TYPE_BITFIELD, + PROBE_TYPE_END, +}; + #define PF_FL_UPROBE 1 #define PF_FL_RW 2 #define for_each_probe_cache_entry(entry, pcache) \ @@ -54,6 +63,7 @@ struct probe_cache_entry *probe_cache__find(struct probe_cache *pcache, struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache, const char *group, const char *event); int probe_cache__show_all_caches(struct strfilter *filter); +bool probe_type_is_available(enum probe_type type); #else /* ! HAVE_LIBELF_SUPPORT */ static inline struct probe_cache *probe_cache__new(const char *tgt __maybe_unused) { diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 5c290c682afe..8daca4fc1f8d 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -39,6 +39,7 @@ #include "util.h" #include "symbol.h" #include "probe-finder.h" +#include "probe-file.h" /* Kprobe tracer basic type is up to u64 */ #define MAX_BASIC_TYPE_BITS 64 @@ -170,6 +171,7 @@ static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs) */ static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, Dwarf_Op *fb_ops, Dwarf_Die *sp_die, + unsigned int machine, struct probe_trace_arg *tvar) { Dwarf_Attribute attr; @@ -265,7 +267,7 @@ static_var: if (!tvar) return ret2; - regs = get_arch_regstr(regn); + regs = get_dwarf_regstr(regn, machine); if (!regs) { /* This should be a bug in DWARF or this tool */ pr_warning("Mapping for the register number %u " @@ -297,13 +299,13 @@ static int convert_variable_type(Dwarf_Die *vr_die, char sbuf[STRERR_BUFSIZE]; int bsize, boffs, total; int ret; - char sign; + char prefix; /* TODO: check all types */ - if (cast && strcmp(cast, "string") != 0 && + if (cast && strcmp(cast, "string") != 0 && strcmp(cast, "x") != 0 && strcmp(cast, "s") != 0 && strcmp(cast, "u") != 0) { /* Non string type is OK */ - /* and respect signedness cast */ + /* and respect signedness/hexadecimal cast */ tvar->type = strdup(cast); return (tvar->type == NULL) ? -ENOMEM : 0; } @@ -365,11 +367,15 @@ static int convert_variable_type(Dwarf_Die *vr_die, } if (cast && (strcmp(cast, "u") == 0)) - sign = 'u'; + prefix = 'u'; else if (cast && (strcmp(cast, "s") == 0)) - sign = 's'; + prefix = 's'; + else if (cast && (strcmp(cast, "x") == 0) && + probe_type_is_available(PROBE_TYPE_X)) + prefix = 'x'; else - sign = die_is_signed_type(&type) ? 's' : 'u'; + prefix = die_is_signed_type(&type) ? 's' : + probe_type_is_available(PROBE_TYPE_X) ? 'x' : 'u'; ret = dwarf_bytesize(&type); if (ret <= 0) @@ -383,7 +389,7 @@ static int convert_variable_type(Dwarf_Die *vr_die, dwarf_diename(&type), MAX_BASIC_TYPE_BITS); ret = MAX_BASIC_TYPE_BITS; } - ret = snprintf(buf, 16, "%c%d", sign, ret); + ret = snprintf(buf, 16, "%c%d", prefix, ret); formatted: if (ret < 0 || ret >= 16) { @@ -538,7 +544,7 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) dwarf_diename(vr_die)); ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops, - &pf->sp_die, pf->tvar); + &pf->sp_die, pf->machine, pf->tvar); if (ret == -ENOENT || ret == -EINVAL) { pr_err("Failed to find the location of the '%s' variable at this address.\n" " Perhaps it has been optimized out.\n" @@ -901,6 +907,38 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) return die_walk_lines(sp_die, probe_point_lazy_walker, pf); } +static void skip_prologue(Dwarf_Die *sp_die, struct probe_finder *pf) +{ + struct perf_probe_point *pp = &pf->pev->point; + + /* Not uprobe? */ + if (!pf->pev->uprobes) + return; + + /* Compiled with optimization? */ + if (die_is_optimized_target(&pf->cu_die)) + return; + + /* Don't know entrypc? */ + if (!pf->addr) + return; + + /* Only FUNC and FUNC@SRC are eligible. */ + if (!pp->function || pp->line || pp->retprobe || pp->lazy_line || + pp->offset || pp->abs_address) + return; + + /* Not interested in func parameter? */ + if (!perf_probe_with_var(pf->pev)) + return; + + pr_info("Target program is compiled without optimization. Skipping prologue.\n" + "Probe on address 0x%" PRIx64 " to force probing at the function entry.\n\n", + pf->addr); + + die_skip_prologue(sp_die, &pf->cu_die, &pf->addr); +} + static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) { struct probe_finder *pf = data; @@ -963,6 +1001,7 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) if (pp->lazy_line) param->retval = find_probe_point_lazy(sp_die, pf); else { + skip_prologue(sp_die, pf); pf->addr += pp->offset; /* TODO: Check the address in this function */ param->retval = call_probe_finder(sp_die, pf); @@ -1101,11 +1140,8 @@ static int debuginfo__find_probes(struct debuginfo *dbg, struct probe_finder *pf) { int ret = 0; - -#if _ELFUTILS_PREREQ(0, 142) Elf *elf; GElf_Ehdr ehdr; - GElf_Shdr shdr; if (pf->cfi_eh || pf->cfi_dbg) return debuginfo__find_probe_location(dbg, pf); @@ -1118,11 +1154,18 @@ static int debuginfo__find_probes(struct debuginfo *dbg, if (gelf_getehdr(elf, &ehdr) == NULL) return -EINVAL; - if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) && - shdr.sh_type == SHT_PROGBITS) - pf->cfi_eh = dwarf_getcfi_elf(elf); + pf->machine = ehdr.e_machine; + +#if _ELFUTILS_PREREQ(0, 142) + do { + GElf_Shdr shdr; + + if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) && + shdr.sh_type == SHT_PROGBITS) + pf->cfi_eh = dwarf_getcfi_elf(elf); - pf->cfi_dbg = dwarf_getcfi(dbg->dbg); + pf->cfi_dbg = dwarf_getcfi(dbg->dbg); + } while (0); #endif ret = debuginfo__find_probe_location(dbg, pf); @@ -1150,7 +1193,7 @@ static int copy_variables_cb(Dwarf_Die *die_mem, void *data) (tag == DW_TAG_variable && vf->vars)) { if (convert_variable_location(die_mem, vf->pf->addr, vf->pf->fb_ops, &pf->sp_die, - NULL) == 0) { + pf->machine, NULL) == 0) { vf->args[vf->nargs].var = (char *)dwarf_diename(die_mem); if (vf->args[vf->nargs].var == NULL) { vf->ret = -ENOMEM; @@ -1313,7 +1356,7 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data) tag == DW_TAG_variable) { ret = convert_variable_location(die_mem, af->pf.addr, af->pf.fb_ops, &af->pf.sp_die, - NULL); + af->pf.machine, NULL); if (ret == 0 || ret == -ERANGE) { int ret2; bool externs = !af->child; diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h index 51137fccb9c8..f1d8558f498e 100644 --- a/tools/perf/util/probe-finder.h +++ b/tools/perf/util/probe-finder.h @@ -80,6 +80,7 @@ struct probe_finder { Dwarf_CFI *cfi_dbg; #endif Dwarf_Op *fb_ops; /* Frame base attribute */ + unsigned int machine; /* Target machine arch */ struct perf_probe_arg *pvar; /* Current target variable */ struct probe_trace_arg *tvar; /* Current result variable */ }; diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index 5d1eb1ccd96c..e55a132f69b7 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c @@ -25,6 +25,7 @@ #include <ctype.h> #include <errno.h> #include <linux/bitmap.h> +#include <linux/time64.h> #include "../util.h" #include <EXTERN.h> @@ -359,8 +360,8 @@ static void perl_process_tracepoint(struct perf_sample *sample, if (!test_and_set_bit(event->id, events_defined)) define_event_symbols(event, handler, event->print_fmt.args); - s = nsecs / NSECS_PER_SEC; - ns = nsecs - s * NSECS_PER_SEC; + s = nsecs / NSEC_PER_SEC; + ns = nsecs - s * NSEC_PER_SEC; scripting_context->event_data = data; scripting_context->pevent = evsel->tp_format->pevent; diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index e0203b979474..089438da1f7f 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -27,6 +27,7 @@ #include <stdbool.h> #include <errno.h> #include <linux/bitmap.h> +#include <linux/time64.h> #include "../../perf.h" #include "../debug.h" @@ -426,8 +427,8 @@ static void python_process_tracepoint(struct perf_sample *sample, if (!dict) Py_FatalError("couldn't create Python dict"); } - s = nsecs / NSECS_PER_SEC; - ns = nsecs - s * NSECS_PER_SEC; + s = nsecs / NSEC_PER_SEC; + ns = nsecs - s * NSEC_PER_SEC; scripting_context->event_data = data; scripting_context->pevent = evsel->tp_format->pevent; diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 3d3cb8392c86..1884d7f9b9d2 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -11,7 +11,7 @@ regex_t parent_regex; const char default_parent_pattern[] = "^sys_|^do_page_fault"; const char *parent_pattern = default_parent_pattern; -const char default_sort_order[] = "comm,dso,symbol"; +const char *default_sort_order = "comm,dso,symbol"; const char default_branch_sort_order[] = "comm,dso_from,symbol_from,symbol_to,cycles"; const char default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked"; const char default_top_sort_order[] = "dso,symbol"; @@ -1492,7 +1492,8 @@ void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists) } static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, - struct hists *hists) + struct hists *hists, int line __maybe_unused, + int *span __maybe_unused) { struct hpp_sort_entry *hse; size_t len = fmt->user_len; @@ -1797,7 +1798,9 @@ static void update_dynamic_len(struct hpp_dynamic_entry *hde, } static int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, - struct hists *hists __maybe_unused) + struct hists *hists __maybe_unused, + int line __maybe_unused, + int *span __maybe_unused) { struct hpp_dynamic_entry *hde; size_t len = fmt->user_len; diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 7ca37ea17395..9505483cb95c 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -28,7 +28,7 @@ extern const char *sort_order; extern const char *field_order; extern const char default_parent_pattern[]; extern const char *parent_pattern; -extern const char default_sort_order[]; +extern const char *default_sort_order; extern regex_t ignore_callees_regex; extern int have_ignore_callees; extern enum sort_mode sort__mode; @@ -40,6 +40,7 @@ extern struct sort_entry sort_dso_from; extern struct sort_entry sort_dso_to; extern struct sort_entry sort_sym_from; extern struct sort_entry sort_sym_to; +extern struct sort_entry sort_srcline; extern enum sort_type sort__first_dimension; extern const char default_mem_sort_order[]; diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c index eec6c1149f44..1cbada2dc6be 100644 --- a/tools/perf/util/svghelper.c +++ b/tools/perf/util/svghelper.c @@ -18,6 +18,7 @@ #include <unistd.h> #include <string.h> #include <linux/bitmap.h> +#include <linux/time64.h> #include "perf.h" #include "svghelper.h" @@ -274,14 +275,14 @@ static char *time_to_string(u64 duration) text[0] = 0; - if (duration < 1000) /* less than 1 usec */ + if (duration < NSEC_PER_USEC) /* less than 1 usec */ return text; - if (duration < 1000 * 1000) { /* less than 1 msec */ - sprintf(text, "%.1f us", duration / 1000.0); + if (duration < NSEC_PER_MSEC) { /* less than 1 msec */ + sprintf(text, "%.1f us", duration / (double)NSEC_PER_USEC); return text; } - sprintf(text, "%.1f ms", duration / 1000.0 / 1000); + sprintf(text, "%.1f ms", duration / (double)NSEC_PER_MSEC); return text; } @@ -297,7 +298,7 @@ void svg_waiting(int Yslot, int cpu, u64 start, u64 end, const char *backtrace) style = "waiting"; - if (end-start > 10 * 1000000) /* 10 msec */ + if (end-start > 10 * NSEC_PER_MSEC) /* 10 msec */ style = "WAITING"; text = time_to_string(end-start); diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index a811c13a74d6..99400b0e8f2a 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -206,6 +206,37 @@ Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, return NULL; } +static bool want_demangle(bool is_kernel_sym) +{ + return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle; +} + +static char *demangle_sym(struct dso *dso, int kmodule, const char *elf_name) +{ + int demangle_flags = verbose ? (DMGL_PARAMS | DMGL_ANSI) : DMGL_NO_OPTS; + char *demangled = NULL; + + /* + * We need to figure out if the object was created from C++ sources + * DWARF DW_compile_unit has this, but we don't always have access + * to it... + */ + if (!want_demangle(dso->kernel || kmodule)) + return demangled; + + demangled = bfd_demangle(NULL, elf_name, demangle_flags); + if (demangled == NULL) + demangled = java_demangle_sym(elf_name, JAVA_DEMANGLE_NORET); + else if (rust_is_mangled(demangled)) + /* + * Input to Rust demangling is the BFD-demangled + * name which it Rust-demangles in place. + */ + rust_demangle_sym(demangled); + + return demangled; +} + #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ idx < nr_entries; \ @@ -223,8 +254,7 @@ Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, * And always look at the original dso, not at debuginfo packages, that * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). */ -int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map *map, - symbol_filter_t filter) +int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map *map) { uint32_t nr_rel_entries, idx; GElf_Sym sym; @@ -301,45 +331,53 @@ int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map * elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_rel_entries) { + const char *elf_name = NULL; + char *demangled = NULL; symidx = GELF_R_SYM(pos->r_info); plt_offset += shdr_plt.sh_entsize; gelf_getsym(syms, symidx, &sym); + + elf_name = elf_sym__name(&sym, symstrs); + demangled = demangle_sym(dso, 0, elf_name); + if (demangled != NULL) + elf_name = demangled; snprintf(sympltname, sizeof(sympltname), - "%s@plt", elf_sym__name(&sym, symstrs)); + "%s@plt", elf_name); + free(demangled); f = symbol__new(plt_offset, shdr_plt.sh_entsize, STB_GLOBAL, sympltname); if (!f) goto out_elf_end; - if (filter && filter(map, f)) - symbol__delete(f); - else { - symbols__insert(&dso->symbols[map->type], f); - ++nr; - } + symbols__insert(&dso->symbols[map->type], f); + ++nr; } } else if (shdr_rel_plt.sh_type == SHT_REL) { GElf_Rel pos_mem, *pos; elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_rel_entries) { + const char *elf_name = NULL; + char *demangled = NULL; symidx = GELF_R_SYM(pos->r_info); plt_offset += shdr_plt.sh_entsize; gelf_getsym(syms, symidx, &sym); + + elf_name = elf_sym__name(&sym, symstrs); + demangled = demangle_sym(dso, 0, elf_name); + if (demangled != NULL) + elf_name = demangled; snprintf(sympltname, sizeof(sympltname), - "%s@plt", elf_sym__name(&sym, symstrs)); + "%s@plt", elf_name); + free(demangled); f = symbol__new(plt_offset, shdr_plt.sh_entsize, STB_GLOBAL, sympltname); if (!f) goto out_elf_end; - if (filter && filter(map, f)) - symbol__delete(f); - else { - symbols__insert(&dso->symbols[map->type], f); - ++nr; - } + symbols__insert(&dso->symbols[map->type], f); + ++nr; } } @@ -685,7 +723,7 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name, } /* Always reject images with a mismatched build-id: */ - if (dso->has_build_id) { + if (dso->has_build_id && !symbol_conf.ignore_vmlinux_buildid) { u8 build_id[BUILD_ID_SIZE]; if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0) { @@ -775,17 +813,11 @@ static u64 ref_reloc(struct kmap *kmap) return 0; } -static bool want_demangle(bool is_kernel_sym) -{ - return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle; -} - void __weak arch__sym_update(struct symbol *s __maybe_unused, GElf_Sym *sym __maybe_unused) { } -int dso__load_sym(struct dso *dso, struct map *map, - struct symsrc *syms_ss, struct symsrc *runtime_ss, - symbol_filter_t filter, int kmodule) +int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, + struct symsrc *runtime_ss, int kmodule) { struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL; struct map_groups *kmaps = kmap ? map__kmaps(map) : NULL; @@ -1070,29 +1102,10 @@ int dso__load_sym(struct dso *dso, struct map *map, sym.st_value -= shdr.sh_addr - shdr.sh_offset; } new_symbol: - /* - * We need to figure out if the object was created from C++ sources - * DWARF DW_compile_unit has this, but we don't always have access - * to it... - */ - if (want_demangle(dso->kernel || kmodule)) { - int demangle_flags = DMGL_NO_OPTS; - if (verbose) - demangle_flags = DMGL_PARAMS | DMGL_ANSI; - - demangled = bfd_demangle(NULL, elf_name, demangle_flags); - if (demangled == NULL) - demangled = java_demangle_sym(elf_name, JAVA_DEMANGLE_NORET); - else if (rust_is_mangled(demangled)) - /* - * Input to Rust demangling is the BFD-demangled - * name which it Rust-demangles in place. - */ - rust_demangle_sym(demangled); + demangled = demangle_sym(dso, kmodule, elf_name); + if (demangled != NULL) + elf_name = demangled; - if (demangled != NULL) - elf_name = demangled; - } f = symbol__new(sym.st_value, sym.st_size, GELF_ST_BIND(sym.st_info), elf_name); free(demangled); @@ -1101,21 +1114,16 @@ new_symbol: arch__sym_update(f, &sym); - if (filter && filter(curr_map, f)) - symbol__delete(f); - else { - symbols__insert(&curr_dso->symbols[curr_map->type], f); - nr++; - } + __symbols__insert(&curr_dso->symbols[curr_map->type], f, dso->kernel); + nr++; } /* * For misannotated, zeroed, ASM function sizes. */ if (nr > 0) { - if (!symbol_conf.allow_aliases) - symbols__fixup_duplicate(&dso->symbols[map->type]); symbols__fixup_end(&dso->symbols[map->type]); + symbols__fixup_duplicate(&dso->symbols[map->type]); if (kmap) { /* * We need to fixup this here too because we create new diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c index 48906333a858..11cdde980545 100644 --- a/tools/perf/util/symbol-minimal.c +++ b/tools/perf/util/symbol-minimal.c @@ -287,8 +287,7 @@ void symsrc__destroy(struct symsrc *ss) int dso__synthesize_plt_symbols(struct dso *dso __maybe_unused, struct symsrc *ss __maybe_unused, - struct map *map __maybe_unused, - symbol_filter_t filter __maybe_unused) + struct map *map __maybe_unused) { return 0; } @@ -334,7 +333,6 @@ enum dso_type dso__type_fd(int fd) int dso__load_sym(struct dso *dso, struct map *map __maybe_unused, struct symsrc *ss, struct symsrc *runtime_ss __maybe_unused, - symbol_filter_t filter __maybe_unused, int kmodule __maybe_unused) { unsigned char build_id[BUILD_ID_SIZE]; diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 37e8d20ae03e..19c9c558454f 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -9,6 +9,7 @@ #include <fcntl.h> #include <unistd.h> #include <inttypes.h> +#include "annotate.h" #include "build-id.h" #include "util.h" #include "debug.h" @@ -23,10 +24,10 @@ #include <symbol/kallsyms.h> #include <sys/utsname.h> -static int dso__load_kernel_sym(struct dso *dso, struct map *map, - symbol_filter_t filter); -static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, - symbol_filter_t filter); +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); + int vmlinux_path__nr_entries; char **vmlinux_path; @@ -152,6 +153,9 @@ void symbols__fixup_duplicate(struct rb_root *symbols) struct rb_node *nd; struct symbol *curr, *next; + if (symbol_conf.allow_aliases) + return; + nd = rb_first(symbols); while (nd) { @@ -235,8 +239,13 @@ struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name) if (sym == NULL) return NULL; - if (symbol_conf.priv_size) + if (symbol_conf.priv_size) { + if (symbol_conf.init_annotation) { + struct annotation *notes = (void *)sym; + pthread_mutex_init(¬es->lock, NULL); + } sym = ((void *)sym) + symbol_conf.priv_size; + } sym->start = start; sym->end = len ? start + len : start; @@ -268,13 +277,24 @@ void symbols__delete(struct rb_root *symbols) } } -void symbols__insert(struct rb_root *symbols, struct symbol *sym) +void __symbols__insert(struct rb_root *symbols, struct symbol *sym, bool kernel) { struct rb_node **p = &symbols->rb_node; struct rb_node *parent = NULL; const u64 ip = sym->start; struct symbol *s; + if (kernel) { + const char *name = sym->name; + /* + * ppc64 uses function descriptors and appends a '.' to the + * start of every instruction address. Remove it. + */ + if (name[0] == '.') + name++; + sym->idle = symbol__is_idle(name); + } + while (*p != NULL) { parent = *p; s = rb_entry(parent, struct symbol, rb_node); @@ -287,6 +307,11 @@ void symbols__insert(struct rb_root *symbols, struct symbol *sym) rb_insert_color(&sym->rb_node, symbols); } +void symbols__insert(struct rb_root *symbols, struct symbol *sym) +{ + __symbols__insert(symbols, sym, false); +} + static struct symbol *symbols__find(struct rb_root *symbols, u64 ip) { struct rb_node *n; @@ -415,7 +440,7 @@ void dso__reset_find_symbol_cache(struct dso *dso) void dso__insert_symbol(struct dso *dso, enum map_type type, struct symbol *sym) { - symbols__insert(&dso->symbols[type], sym); + __symbols__insert(&dso->symbols[type], sym, dso->kernel); /* update the symbol cache if necessary */ if (dso->last_find_result[type].addr >= sym->start && @@ -537,7 +562,7 @@ struct process_kallsyms_args { * These are symbols in the kernel image, so make sure that * sym is from a kernel DSO. */ -bool symbol__is_idle(struct symbol *sym) +static bool symbol__is_idle(const char *name) { const char * const idle_symbols[] = { "cpu_idle", @@ -554,14 +579,10 @@ bool symbol__is_idle(struct symbol *sym) "pseries_dedicated_idle_sleep", NULL }; - int i; - if (!sym) - return false; - for (i = 0; idle_symbols[i]; i++) { - if (!strcmp(idle_symbols[i], sym->name)) + if (!strcmp(idle_symbols[i], name)) return true; } @@ -590,7 +611,7 @@ static int map__process_kallsym_symbol(void *arg, const char *name, * We will pass the symbols to the filter later, in * map__split_kallsyms, when we have split the maps per module */ - symbols__insert(root, sym); + __symbols__insert(root, sym, !strchr(name, '[')); return 0; } @@ -607,8 +628,7 @@ static int dso__load_all_kallsyms(struct dso *dso, const char *filename, return kallsyms__parse(filename, &args, map__process_kallsym_symbol); } -static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map, - symbol_filter_t filter) +static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map) { struct map_groups *kmaps = map__kmaps(map); struct map *curr_map; @@ -637,7 +657,7 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map, curr_map = map_groups__find(kmaps, map->type, pos->start); - if (!curr_map || (filter && filter(curr_map, pos))) { + if (!curr_map) { symbol__delete(pos); continue; } @@ -660,8 +680,7 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map, * kernel range is broken in several maps, named [kernel].N, as we don't have * the original ELF section names vmlinux have. */ -static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta, - symbol_filter_t filter) +static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta) { struct map_groups *kmaps = map__kmaps(map); struct machine *machine; @@ -738,7 +757,7 @@ static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta, if (count == 0) { curr_map = map; - goto filter_symbol; + goto add_symbol; } if (dso->kernel == DSO_TYPE_GUEST_KERNEL) @@ -770,18 +789,18 @@ static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta, pos->start -= delta; pos->end -= delta; } -filter_symbol: - if (filter && filter(curr_map, pos)) { -discard_symbol: rb_erase(&pos->rb_node, root); - symbol__delete(pos); - } else { - if (curr_map != map) { - rb_erase(&pos->rb_node, root); - symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); - ++moved; - } else - ++count; - } +add_symbol: + if (curr_map != map) { + rb_erase(&pos->rb_node, root); + symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); + ++moved; + } else + ++count; + + continue; +discard_symbol: + rb_erase(&pos->rb_node, root); + symbol__delete(pos); } if (curr_map != map && @@ -1221,7 +1240,7 @@ static int kallsyms__delta(struct map *map, const char *filename, u64 *delta) } int __dso__load_kallsyms(struct dso *dso, const char *filename, - struct map *map, bool no_kcore, symbol_filter_t filter) + struct map *map, bool no_kcore) { u64 delta = 0; @@ -1234,8 +1253,8 @@ int __dso__load_kallsyms(struct dso *dso, const char *filename, if (kallsyms__delta(map, filename, &delta)) return -1; - symbols__fixup_duplicate(&dso->symbols[map->type]); symbols__fixup_end(&dso->symbols[map->type]); + symbols__fixup_duplicate(&dso->symbols[map->type]); if (dso->kernel == DSO_TYPE_GUEST_KERNEL) dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; @@ -1243,19 +1262,18 @@ int __dso__load_kallsyms(struct dso *dso, const char *filename, dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS; if (!no_kcore && !dso__load_kcore(dso, map, filename)) - return dso__split_kallsyms_for_kcore(dso, map, filter); + return dso__split_kallsyms_for_kcore(dso, map); else - return dso__split_kallsyms(dso, map, delta, filter); + return dso__split_kallsyms(dso, map, delta); } int dso__load_kallsyms(struct dso *dso, const char *filename, - struct map *map, symbol_filter_t filter) + struct map *map) { - return __dso__load_kallsyms(dso, filename, map, false, filter); + return __dso__load_kallsyms(dso, filename, map, false); } -static int dso__load_perf_map(struct dso *dso, struct map *map, - symbol_filter_t filter) +static int dso__load_perf_map(struct dso *dso, struct map *map) { char *line = NULL; size_t n; @@ -1297,12 +1315,8 @@ static int dso__load_perf_map(struct dso *dso, struct map *map, if (sym == NULL) goto out_delete_line; - if (filter && filter(map, sym)) - symbol__delete(sym); - else { - symbols__insert(&dso->symbols[map->type], sym); - nr_syms++; - } + symbols__insert(&dso->symbols[map->type], sym); + nr_syms++; } free(line); @@ -1358,7 +1372,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod, } } -int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) +int dso__load(struct dso *dso, struct map *map) { char *name; int ret = -1; @@ -1381,9 +1395,9 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) if (dso->kernel) { if (dso->kernel == DSO_TYPE_KERNEL) - ret = dso__load_kernel_sym(dso, map, filter); + ret = dso__load_kernel_sym(dso, map); else if (dso->kernel == DSO_TYPE_GUEST_KERNEL) - ret = dso__load_guest_kernel_sym(dso, map, filter); + ret = dso__load_guest_kernel_sym(dso, map); goto out; } @@ -1407,7 +1421,7 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) goto out; } - ret = dso__load_perf_map(dso, map, filter); + ret = dso__load_perf_map(dso, map); dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT : DSO_BINARY_TYPE__NOT_FOUND; goto out; @@ -1498,14 +1512,14 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) kmod = true; if (syms_ss) - ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, kmod); + ret = dso__load_sym(dso, map, syms_ss, runtime_ss, kmod); else ret = -1; if (ret > 0) { int nr_plt; - nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss, map, filter); + nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss, map); if (nr_plt > 0) ret += nr_plt; } @@ -1544,8 +1558,7 @@ out_unlock: } int dso__load_vmlinux(struct dso *dso, struct map *map, - const char *vmlinux, bool vmlinux_allocated, - symbol_filter_t filter) + const char *vmlinux, bool vmlinux_allocated) { int err = -1; struct symsrc ss; @@ -1565,7 +1578,7 @@ int dso__load_vmlinux(struct dso *dso, struct map *map, if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type)) return -1; - err = dso__load_sym(dso, map, &ss, &ss, filter, 0); + err = dso__load_sym(dso, map, &ss, &ss, 0); symsrc__destroy(&ss); if (err > 0) { @@ -1581,8 +1594,7 @@ int dso__load_vmlinux(struct dso *dso, struct map *map, return err; } -int dso__load_vmlinux_path(struct dso *dso, struct map *map, - symbol_filter_t filter) +int dso__load_vmlinux_path(struct dso *dso, struct map *map) { int i, err = 0; char *filename = NULL; @@ -1591,7 +1603,7 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map, vmlinux_path__nr_entries + 1); for (i = 0; i < vmlinux_path__nr_entries; ++i) { - err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter); + err = dso__load_vmlinux(dso, map, vmlinux_path[i], false); if (err > 0) goto out; } @@ -1599,7 +1611,7 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map, if (!symbol_conf.ignore_vmlinux_buildid) filename = dso__build_id_filename(dso, NULL, 0); if (filename != NULL) { - err = dso__load_vmlinux(dso, map, filename, true, filter); + err = dso__load_vmlinux(dso, map, filename, true); if (err > 0) goto out; free(filename); @@ -1713,8 +1725,7 @@ proc_kallsyms: return strdup(path); } -static int dso__load_kernel_sym(struct dso *dso, struct map *map, - symbol_filter_t filter) +static int dso__load_kernel_sym(struct dso *dso, struct map *map) { int err; const char *kallsyms_filename = NULL; @@ -1740,12 +1751,11 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map, } if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) { - return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name, - false, filter); + return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name, false); } if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) { - err = dso__load_vmlinux_path(dso, map, filter); + err = dso__load_vmlinux_path(dso, map); if (err > 0) return err; } @@ -1761,7 +1771,7 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map, kallsyms_filename = kallsyms_allocated_filename; do_kallsyms: - err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); + err = dso__load_kallsyms(dso, kallsyms_filename, map); if (err > 0) pr_debug("Using %s for symbols\n", kallsyms_filename); free(kallsyms_allocated_filename); @@ -1776,8 +1786,7 @@ do_kallsyms: return err; } -static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, - symbol_filter_t filter) +static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map) { int err; const char *kallsyms_filename = NULL; @@ -1799,7 +1808,7 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, if (symbol_conf.default_guest_vmlinux_name != NULL) { err = dso__load_vmlinux(dso, map, symbol_conf.default_guest_vmlinux_name, - false, filter); + false); return err; } @@ -1811,7 +1820,7 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, kallsyms_filename = path; } - err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); + err = dso__load_kallsyms(dso, kallsyms_filename, map); if (err > 0) pr_debug("Using %s for symbols\n", kallsyms_filename); if (err > 0 && !dso__is_kcore(dso)) { @@ -1948,6 +1957,23 @@ static bool symbol__read_kptr_restrict(void) return value; } +int symbol__annotation_init(void) +{ + if (symbol_conf.initialized) { + pr_err("Annotation needs to be init before symbol__init()\n"); + return -1; + } + + if (symbol_conf.init_annotation) { + pr_warning("Annotation being initialized multiple times\n"); + return 0; + } + + symbol_conf.priv_size += sizeof(struct annotation); + symbol_conf.init_annotation = true; + return 0; +} + int symbol__init(struct perf_env *env) { const char *symfs; diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 699f7cbcfe72..0dacfb7d5b67 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -57,7 +57,7 @@ struct symbol { u64 end; u16 namelen; u8 binding; - bool ignore; + u8 idle:1; u8 arch_sym; char name[0]; }; @@ -88,6 +88,7 @@ struct symbol_conf { unsigned short priv_size; unsigned short nr_events; bool try_vmlinux_path, + init_annotation, force, ignore_vmlinux, ignore_vmlinux_buildid, @@ -240,16 +241,13 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name, bool symsrc__has_symtab(struct symsrc *ss); bool symsrc__possibly_runtime(struct symsrc *ss); -int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter); +int dso__load(struct dso *dso, struct map *map); int dso__load_vmlinux(struct dso *dso, struct map *map, - const char *vmlinux, bool vmlinux_allocated, - symbol_filter_t filter); -int dso__load_vmlinux_path(struct dso *dso, struct map *map, - symbol_filter_t filter); + const char *vmlinux, bool vmlinux_allocated); +int dso__load_vmlinux_path(struct dso *dso, struct map *map); int __dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map, - bool no_kcore, symbol_filter_t filter); -int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map, - symbol_filter_t filter); + bool no_kcore); +int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map); void dso__insert_symbol(struct dso *dso, enum map_type type, struct symbol *sym); @@ -277,6 +275,8 @@ struct perf_env; int symbol__init(struct perf_env *env); void symbol__exit(void); void symbol__elf_init(void); +int symbol__annotation_init(void); + struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name); size_t __symbol__fprintf_symname_offs(const struct symbol *sym, const struct addr_location *al, @@ -291,16 +291,15 @@ size_t symbol__fprintf(struct symbol *sym, FILE *fp); bool symbol_type__is_a(char symbol_type, enum map_type map_type); bool symbol__restricted_filename(const char *filename, const char *restricted_filename); -bool symbol__is_idle(struct symbol *sym); int symbol__config_symfs(const struct option *opt __maybe_unused, const char *dir, int unset __maybe_unused); int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, - struct symsrc *runtime_ss, symbol_filter_t filter, - int kmodule); + struct symsrc *runtime_ss, int kmodule); int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, - struct map *map, symbol_filter_t filter); + struct map *map); +void __symbols__insert(struct rb_root *symbols, struct symbol *sym, bool kernel); void symbols__insert(struct rb_root *symbols, struct symbol *sym); void symbols__fixup_duplicate(struct rb_root *symbols); void symbols__fixup_end(struct rb_root *symbols); diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index cee559d8c9e8..85c56800f17a 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -15,6 +15,7 @@ #include <byteswap.h> #include <linux/kernel.h> #include <linux/log2.h> +#include <linux/time64.h> #include <unistd.h> #include "callchain.h" #include "strlist.h" diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index e5f55477491d..43899e0d6fa1 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -179,10 +179,6 @@ static inline void *zalloc(size_t size) #undef tolower #undef toupper -#ifndef NSEC_PER_MSEC -#define NSEC_PER_MSEC 1000000L -#endif - int parse_nsec_time(const char *str, u64 *ptime); extern unsigned char sane_ctype[256]; |