perf/core improvements and fixes:
New features: - Allow sorting by symbol_size in 'perf report' and 'perf top' (Charles Baylis) E.g.: # perf report -s symbol_size,symbol Samples: 9K of event 'cycles:k', Event count (approx.): 2870461623 Overhead Symbol size Symbol 14.55% 326 [k] flush_tlb_mm_range 7.20% 1045 [k] filemap_map_pages 5.82% 124 [k] vma_interval_tree_insert 5.18% 2430 [k] unmap_page_range 2.57% 571 [k] vma_interval_tree_remove 1.94% 494 [k] page_add_file_rmap 1.82% 740 [k] page_remove_rmap 1.66% 1017 [k] release_pages 1.57% 1636 [k] update_blocked_averages 1.57% 76 [k] unlock_page - Add support for -p/--pid, -a/--all-cpus and -C/--cpu in 'perf ftrace' (Namhyung Kim) Change in behaviour: - Make system wide (-a) the default option if no target was specified and one of following conditions is met: - No workload specified (current behaviour) - A workload is specified but all requested events are system wide ones, like uncore ones. (Jiri Olsa) Fixes: - Add missing initialization to the instruction decoder used in the intel PT/BTS code, which was causing lots of failures in 'perf test', looking for a value when there was none (Adrian Hunter) Infrastructure: - Add arch code needed to adopt the kernel's refcount_t to aid in catching bugs when using atomic_t as a reference counter, basically cmpxchg related functions (Arnaldo Carvalho de Melo) - Convert the code using atomic_t as reference counts to refcount_t (Elena Rashetova) - Add feature test for sched_getcpu() to more easily check for its presence in the many libc implementations and accross different versions of such C libraries (Arnaldo Carvalho de Melo) - Issue a HW watchdog disable hint in 'perf stat' for when some of the requested events can't get counted because a PMU counter is taken by that watchdog (Borislav Petkov). - Add mapping for Intel's KnightsMill PMU events (Karol Wachowski) Documentation: - Clarify the term 'convergence' in: perf bench numa numa-mem -h --show_convergence (Jiri Olsa) Kernel code: - Ensure probe location is at function entry in kretprobes (Naveen N. Rao) - Allow return probes with offsets and absolute addresses (Naveen N. Rao) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABCAAGBQJYvbmTAAoJENZQFvNTUqpAN80QAJ2ETcTosR9fo06VrT2HqRT4 +iGe55wSu261TOekIkXOEW+ww321eNPfy4rIZeLCEFcCd9p03n5JceVbFnOjBuAz Lk6jrKpaH+Ajp56nCLyWH4r3LYLJXdoIydNay4PZ08rl0GgagGqvevD8ZZCEO0sx vjD1TFH2uSOq3UTxKapO++FHwhy+XqZ5S5I+rMuLxg6Qi+rLubXDztzIlcCfQPGx g+zFkaJ/ms9TAtWK25xoj34QXsaqpBsF8qkCE1P8Zdjtnkp6zM2Rx3HvvbRDmgVx /h0b1iua5IVElgnai/84ttJG3Bi6ovRbf/PFy+IceM4Qfx0eQeWmA3CAtcGOh9Gv GTDCcJ7xWZBpM0g1wCk3ks2oApFTA6GkcnIt5alhTse5U3gNmImv3uvuN8d265KL 2oGKps7MH1nWMgpL4G4BNuZg2oqmM/uX9ERiuNjtCqj6WoHy2QSDyEMJN5Od3lYj ar2PPGofHmiacsW3NNMT+LwQ/wL/d2dVfZTopMafeaxRDGTxdqkhLkB/sZT/wexQ ySVijQPO+x0eLSIK/BWdEmD8K6JiYGdpIRDWVW+D043I7iiXFvPgui1bFABJEqn5 mZFa1qT4EQMuuSaLkkxtoOrdoF6YzJJA57sIx2IrouGDapJ2BDegiUOfE0PSp5l0 oeRuFcJYfpITC/TzntE3 =h2yo -----END PGP SIGNATURE----- Merge tag 'perf-core-for-mingo-4.11-20170306' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: New features: - Allow sorting by symbol_size in 'perf report' and 'perf top' (Charles Baylis) E.g.: # perf report -s symbol_size,symbol Samples: 9K of event 'cycles:k', Event count (approx.): 2870461623 Overhead Symbol size Symbol 14.55% 326 [k] flush_tlb_mm_range 7.20% 1045 [k] filemap_map_pages 5.82% 124 [k] vma_interval_tree_insert 5.18% 2430 [k] unmap_page_range 2.57% 571 [k] vma_interval_tree_remove 1.94% 494 [k] page_add_file_rmap 1.82% 740 [k] page_remove_rmap 1.66% 1017 [k] release_pages 1.57% 1636 [k] update_blocked_averages 1.57% 76 [k] unlock_page - Add support for -p/--pid, -a/--all-cpus and -C/--cpu in 'perf ftrace' (Namhyung Kim) Change in behaviour: - Make system wide (-a) the default option if no target was specified and one of following conditions is met: - No workload specified (current behaviour) - A workload is specified but all requested events are system wide ones, like uncore ones. (Jiri Olsa) Fixes: - Add missing initialization to the instruction decoder used in the intel PT/BTS code, which was causing lots of failures in 'perf test', looking for a value when there was none (Adrian Hunter) Infrastructure changes: - Add arch code needed to adopt the kernel's refcount_t to aid in catching bugs when using atomic_t as a reference counter, basically cmpxchg related functions (Arnaldo Carvalho de Melo) - Convert the code using atomic_t as reference counts to refcount_t (Elena Rashetova) - Add feature test for sched_getcpu() to more easily check for its presence in the many libc implementations and accross different versions of such C libraries (Arnaldo Carvalho de Melo) - Issue a HW watchdog disable hint in 'perf stat' for when some of the requested events can't get counted because a PMU counter is taken by that watchdog (Borislav Petkov). - Add mapping for Intel's KnightsMill PMU events (Karol Wachowski) Documentation changes: - Clarify the term 'convergence' in: perf bench numa numa-mem -h --show_convergence (Jiri Olsa) Kernel code changes: - Ensure probe location is at function entry in kretprobes (Naveen N. Rao) - Allow return probes with offsets and absolute addresses (Naveen N. Rao) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
Коммит
84e5b54921
|
@ -12,7 +12,7 @@ kprobes can probe (this means, all functions body except for __kprobes
|
|||
functions). Unlike the Tracepoint based event, this can be added and removed
|
||||
dynamically, on the fly.
|
||||
|
||||
To enable this feature, build your kernel with CONFIG_KPROBE_EVENT=y.
|
||||
To enable this feature, build your kernel with CONFIG_KPROBE_EVENTS=y.
|
||||
|
||||
Similar to the events tracer, this doesn't need to be activated via
|
||||
current_tracer. Instead of that, add probe points via
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
Overview
|
||||
--------
|
||||
Uprobe based trace events are similar to kprobe based trace events.
|
||||
To enable this feature, build your kernel with CONFIG_UPROBE_EVENT=y.
|
||||
To enable this feature, build your kernel with CONFIG_UPROBE_EVENTS=y.
|
||||
|
||||
Similar to the kprobe-event tracer, this doesn't need to be activated via
|
||||
current_tracer. Instead of that, add probe points via
|
||||
|
|
|
@ -609,7 +609,7 @@ CONFIG_SCHED_TRACER=y
|
|||
CONFIG_FTRACE_SYSCALLS=y
|
||||
CONFIG_STACK_TRACER=y
|
||||
CONFIG_BLK_DEV_IO_TRACE=y
|
||||
CONFIG_UPROBE_EVENT=y
|
||||
CONFIG_UPROBE_EVENTS=y
|
||||
CONFIG_FUNCTION_PROFILER=y
|
||||
CONFIG_HIST_TRIGGERS=y
|
||||
CONFIG_TRACE_ENUM_MAP_FILE=y
|
||||
|
|
|
@ -560,7 +560,7 @@ CONFIG_SCHED_TRACER=y
|
|||
CONFIG_FTRACE_SYSCALLS=y
|
||||
CONFIG_STACK_TRACER=y
|
||||
CONFIG_BLK_DEV_IO_TRACE=y
|
||||
CONFIG_UPROBE_EVENT=y
|
||||
CONFIG_UPROBE_EVENTS=y
|
||||
CONFIG_FUNCTION_PROFILER=y
|
||||
CONFIG_HIST_TRIGGERS=y
|
||||
CONFIG_TRACE_ENUM_MAP_FILE=y
|
||||
|
|
|
@ -558,7 +558,7 @@ CONFIG_SCHED_TRACER=y
|
|||
CONFIG_FTRACE_SYSCALLS=y
|
||||
CONFIG_STACK_TRACER=y
|
||||
CONFIG_BLK_DEV_IO_TRACE=y
|
||||
CONFIG_UPROBE_EVENT=y
|
||||
CONFIG_UPROBE_EVENTS=y
|
||||
CONFIG_FUNCTION_PROFILER=y
|
||||
CONFIG_HIST_TRIGGERS=y
|
||||
CONFIG_TRACE_ENUM_MAP_FILE=y
|
||||
|
|
|
@ -179,7 +179,7 @@ CONFIG_FTRACE_SYSCALLS=y
|
|||
CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP=y
|
||||
CONFIG_STACK_TRACER=y
|
||||
CONFIG_BLK_DEV_IO_TRACE=y
|
||||
CONFIG_UPROBE_EVENT=y
|
||||
CONFIG_UPROBE_EVENTS=y
|
||||
CONFIG_FUNCTION_PROFILER=y
|
||||
CONFIG_TRACE_ENUM_MAP_FILE=y
|
||||
CONFIG_KPROBES_SANITY_TEST=y
|
||||
|
|
|
@ -67,7 +67,7 @@
|
|||
#endif
|
||||
|
||||
/* Ensure if the instruction can be boostable */
|
||||
extern int can_boost(kprobe_opcode_t *instruction);
|
||||
extern int can_boost(kprobe_opcode_t *instruction, void *addr);
|
||||
/* Recover instruction if given address is probed */
|
||||
extern unsigned long recover_probed_instruction(kprobe_opcode_t *buf,
|
||||
unsigned long addr);
|
||||
|
|
|
@ -167,12 +167,12 @@ NOKPROBE_SYMBOL(skip_prefixes);
|
|||
* Returns non-zero if opcode is boostable.
|
||||
* RIP relative instructions are adjusted at copying time in 64 bits mode
|
||||
*/
|
||||
int can_boost(kprobe_opcode_t *opcodes)
|
||||
int can_boost(kprobe_opcode_t *opcodes, void *addr)
|
||||
{
|
||||
kprobe_opcode_t opcode;
|
||||
kprobe_opcode_t *orig_opcodes = opcodes;
|
||||
|
||||
if (search_exception_tables((unsigned long)opcodes))
|
||||
if (search_exception_tables((unsigned long)addr))
|
||||
return 0; /* Page fault may occur on this address. */
|
||||
|
||||
retry:
|
||||
|
@ -417,7 +417,7 @@ static int arch_copy_kprobe(struct kprobe *p)
|
|||
* __copy_instruction can modify the displacement of the instruction,
|
||||
* but it doesn't affect boostable check.
|
||||
*/
|
||||
if (can_boost(p->ainsn.insn))
|
||||
if (can_boost(p->ainsn.insn, p->addr))
|
||||
p->ainsn.boostable = 0;
|
||||
else
|
||||
p->ainsn.boostable = -1;
|
||||
|
|
|
@ -178,7 +178,7 @@ static int copy_optimized_instructions(u8 *dest, u8 *src)
|
|||
|
||||
while (len < RELATIVEJUMP_SIZE) {
|
||||
ret = __copy_instruction(dest + len, src + len);
|
||||
if (!ret || !can_boost(dest + len))
|
||||
if (!ret || !can_boost(dest + len, src + len))
|
||||
return -EINVAL;
|
||||
len += ret;
|
||||
}
|
||||
|
|
|
@ -267,6 +267,7 @@ extern int arch_init_kprobes(void);
|
|||
extern void show_registers(struct pt_regs *regs);
|
||||
extern void kprobes_inc_nmissed_count(struct kprobe *p);
|
||||
extern bool arch_within_kprobe_blacklist(unsigned long addr);
|
||||
extern bool arch_function_offset_within_entry(unsigned long offset);
|
||||
|
||||
extern bool within_kprobe_blacklist(unsigned long addr);
|
||||
|
||||
|
|
|
@ -1875,12 +1875,25 @@ static int pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs)
|
|||
}
|
||||
NOKPROBE_SYMBOL(pre_handler_kretprobe);
|
||||
|
||||
bool __weak arch_function_offset_within_entry(unsigned long offset)
|
||||
{
|
||||
return !offset;
|
||||
}
|
||||
|
||||
int register_kretprobe(struct kretprobe *rp)
|
||||
{
|
||||
int ret = 0;
|
||||
struct kretprobe_instance *inst;
|
||||
int i;
|
||||
void *addr;
|
||||
unsigned long offset;
|
||||
|
||||
addr = kprobe_addr(&rp->kp);
|
||||
if (!kallsyms_lookup_size_offset((unsigned long)addr, NULL, &offset))
|
||||
return -EINVAL;
|
||||
|
||||
if (!arch_function_offset_within_entry(offset))
|
||||
return -EINVAL;
|
||||
|
||||
if (kretprobe_blacklist_size) {
|
||||
addr = kprobe_addr(&rp->kp);
|
||||
|
|
|
@ -429,7 +429,7 @@ config BLK_DEV_IO_TRACE
|
|||
|
||||
If unsure, say N.
|
||||
|
||||
config KPROBE_EVENT
|
||||
config KPROBE_EVENTS
|
||||
depends on KPROBES
|
||||
depends on HAVE_REGS_AND_STACK_ACCESS_API
|
||||
bool "Enable kprobes-based dynamic events"
|
||||
|
@ -447,7 +447,7 @@ config KPROBE_EVENT
|
|||
This option is also required by perf-probe subcommand of perf tools.
|
||||
If you want to use perf tools, this option is strongly recommended.
|
||||
|
||||
config UPROBE_EVENT
|
||||
config UPROBE_EVENTS
|
||||
bool "Enable uprobes-based dynamic events"
|
||||
depends on ARCH_SUPPORTS_UPROBES
|
||||
depends on MMU
|
||||
|
@ -466,7 +466,7 @@ config UPROBE_EVENT
|
|||
|
||||
config BPF_EVENTS
|
||||
depends on BPF_SYSCALL
|
||||
depends on (KPROBE_EVENT || UPROBE_EVENT) && PERF_EVENTS
|
||||
depends on (KPROBE_EVENTS || UPROBE_EVENTS) && PERF_EVENTS
|
||||
bool
|
||||
default y
|
||||
help
|
||||
|
|
|
@ -57,7 +57,7 @@ obj-$(CONFIG_EVENT_TRACING) += trace_events_filter.o
|
|||
obj-$(CONFIG_EVENT_TRACING) += trace_events_trigger.o
|
||||
obj-$(CONFIG_HIST_TRIGGERS) += trace_events_hist.o
|
||||
obj-$(CONFIG_BPF_EVENTS) += bpf_trace.o
|
||||
obj-$(CONFIG_KPROBE_EVENT) += trace_kprobe.o
|
||||
obj-$(CONFIG_KPROBE_EVENTS) += trace_kprobe.o
|
||||
obj-$(CONFIG_TRACEPOINTS) += power-traces.o
|
||||
ifeq ($(CONFIG_PM),y)
|
||||
obj-$(CONFIG_TRACEPOINTS) += rpm-traces.o
|
||||
|
@ -66,7 +66,7 @@ ifeq ($(CONFIG_TRACING),y)
|
|||
obj-$(CONFIG_KGDB_KDB) += trace_kdb.o
|
||||
endif
|
||||
obj-$(CONFIG_PROBE_EVENTS) += trace_probe.o
|
||||
obj-$(CONFIG_UPROBE_EVENT) += trace_uprobe.o
|
||||
obj-$(CONFIG_UPROBE_EVENTS) += trace_uprobe.o
|
||||
|
||||
obj-$(CONFIG_TRACEPOINT_BENCHMARK) += trace_benchmark.o
|
||||
|
||||
|
|
|
@ -4341,22 +4341,23 @@ static const char readme_msg[] =
|
|||
"\t\t\t traces\n"
|
||||
#endif
|
||||
#endif /* CONFIG_STACK_TRACER */
|
||||
#ifdef CONFIG_KPROBE_EVENT
|
||||
#ifdef CONFIG_KPROBE_EVENTS
|
||||
" kprobe_events\t\t- Add/remove/show the kernel dynamic events\n"
|
||||
"\t\t\t Write into this file to define/undefine new trace events.\n"
|
||||
#endif
|
||||
#ifdef CONFIG_UPROBE_EVENT
|
||||
#ifdef CONFIG_UPROBE_EVENTS
|
||||
" uprobe_events\t\t- Add/remove/show the userspace dynamic events\n"
|
||||
"\t\t\t Write into this file to define/undefine new trace events.\n"
|
||||
#endif
|
||||
#if defined(CONFIG_KPROBE_EVENT) || defined(CONFIG_UPROBE_EVENT)
|
||||
#if defined(CONFIG_KPROBE_EVENTS) || defined(CONFIG_UPROBE_EVENTS)
|
||||
"\t accepts: event-definitions (one definition per line)\n"
|
||||
"\t Format: p|r[:[<group>/]<event>] <place> [<args>]\n"
|
||||
"\t -:[<group>/]<event>\n"
|
||||
#ifdef CONFIG_KPROBE_EVENT
|
||||
#ifdef CONFIG_KPROBE_EVENTS
|
||||
"\t place: [<module>:]<symbol>[+<offset>]|<memaddr>\n"
|
||||
"place (kretprobe): [<module>:]<symbol>[+<offset>]|<memaddr>\n"
|
||||
#endif
|
||||
#ifdef CONFIG_UPROBE_EVENT
|
||||
#ifdef CONFIG_UPROBE_EVENTS
|
||||
"\t place: <path>:<offset>\n"
|
||||
#endif
|
||||
"\t args: <name>=fetcharg[:type]\n"
|
||||
|
|
|
@ -681,10 +681,6 @@ static int create_trace_kprobe(int argc, char **argv)
|
|||
return -EINVAL;
|
||||
}
|
||||
if (isdigit(argv[1][0])) {
|
||||
if (is_return) {
|
||||
pr_info("Return probe point must be a symbol.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
/* an address specified */
|
||||
ret = kstrtoul(&argv[1][0], 0, (unsigned long *)&addr);
|
||||
if (ret) {
|
||||
|
@ -700,8 +696,9 @@ static int create_trace_kprobe(int argc, char **argv)
|
|||
pr_info("Failed to parse symbol.\n");
|
||||
return ret;
|
||||
}
|
||||
if (offset && is_return) {
|
||||
pr_info("Return probe must be used without offset.\n");
|
||||
if (offset && is_return &&
|
||||
!arch_function_offset_within_entry(offset)) {
|
||||
pr_info("Given offset is not valid for return probe.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -248,7 +248,7 @@ ASSIGN_FETCH_FUNC(file_offset, ftype), \
|
|||
#define FETCH_TYPE_STRING 0
|
||||
#define FETCH_TYPE_STRSIZE 1
|
||||
|
||||
#ifdef CONFIG_KPROBE_EVENT
|
||||
#ifdef CONFIG_KPROBE_EVENTS
|
||||
struct symbol_cache;
|
||||
unsigned long update_symbol_cache(struct symbol_cache *sc);
|
||||
void free_symbol_cache(struct symbol_cache *sc);
|
||||
|
@ -278,7 +278,7 @@ alloc_symbol_cache(const char *sym, long offset)
|
|||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_KPROBE_EVENT */
|
||||
#endif /* CONFIG_KPROBE_EVENTS */
|
||||
|
||||
struct probe_arg {
|
||||
struct fetch_param fetch;
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#define LOCK_PREFIX "\n\tlock; "
|
||||
|
||||
#include <asm/cmpxchg.h>
|
||||
|
||||
/*
|
||||
* Atomic operations that C can't guarantee us. Useful for
|
||||
* resource counting etc..
|
||||
|
@ -62,4 +64,9 @@ static inline int atomic_dec_and_test(atomic_t *v)
|
|||
GEN_UNARY_RMWcc(LOCK_PREFIX "decl", v->counter, "%0", "e");
|
||||
}
|
||||
|
||||
static __always_inline int atomic_cmpxchg(atomic_t *v, int old, int new)
|
||||
{
|
||||
return cmpxchg(&v->counter, old, new);
|
||||
}
|
||||
|
||||
#endif /* _TOOLS_LINUX_ASM_X86_ATOMIC_H */
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
#ifndef TOOLS_ASM_X86_CMPXCHG_H
|
||||
#define TOOLS_ASM_X86_CMPXCHG_H
|
||||
|
||||
#include <linux/compiler.h>
|
||||
|
||||
/*
|
||||
* Non-existant functions to indicate usage errors at link time
|
||||
* (or compile-time if the compiler implements __compiletime_error().
|
||||
*/
|
||||
extern void __cmpxchg_wrong_size(void)
|
||||
__compiletime_error("Bad argument size for cmpxchg");
|
||||
|
||||
/*
|
||||
* Constants for operation sizes. On 32-bit, the 64-bit size it set to
|
||||
* -1 because sizeof will never return -1, thereby making those switch
|
||||
* case statements guaranteeed dead code which the compiler will
|
||||
* eliminate, and allowing the "missing symbol in the default case" to
|
||||
* indicate a usage error.
|
||||
*/
|
||||
#define __X86_CASE_B 1
|
||||
#define __X86_CASE_W 2
|
||||
#define __X86_CASE_L 4
|
||||
#ifdef __x86_64__
|
||||
#define __X86_CASE_Q 8
|
||||
#else
|
||||
#define __X86_CASE_Q -1 /* sizeof will never return -1 */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Atomic compare and exchange. Compare OLD with MEM, if identical,
|
||||
* store NEW in MEM. Return the initial value in MEM. Success is
|
||||
* indicated by comparing RETURN with OLD.
|
||||
*/
|
||||
#define __raw_cmpxchg(ptr, old, new, size, lock) \
|
||||
({ \
|
||||
__typeof__(*(ptr)) __ret; \
|
||||
__typeof__(*(ptr)) __old = (old); \
|
||||
__typeof__(*(ptr)) __new = (new); \
|
||||
switch (size) { \
|
||||
case __X86_CASE_B: \
|
||||
{ \
|
||||
volatile u8 *__ptr = (volatile u8 *)(ptr); \
|
||||
asm volatile(lock "cmpxchgb %2,%1" \
|
||||
: "=a" (__ret), "+m" (*__ptr) \
|
||||
: "q" (__new), "0" (__old) \
|
||||
: "memory"); \
|
||||
break; \
|
||||
} \
|
||||
case __X86_CASE_W: \
|
||||
{ \
|
||||
volatile u16 *__ptr = (volatile u16 *)(ptr); \
|
||||
asm volatile(lock "cmpxchgw %2,%1" \
|
||||
: "=a" (__ret), "+m" (*__ptr) \
|
||||
: "r" (__new), "0" (__old) \
|
||||
: "memory"); \
|
||||
break; \
|
||||
} \
|
||||
case __X86_CASE_L: \
|
||||
{ \
|
||||
volatile u32 *__ptr = (volatile u32 *)(ptr); \
|
||||
asm volatile(lock "cmpxchgl %2,%1" \
|
||||
: "=a" (__ret), "+m" (*__ptr) \
|
||||
: "r" (__new), "0" (__old) \
|
||||
: "memory"); \
|
||||
break; \
|
||||
} \
|
||||
case __X86_CASE_Q: \
|
||||
{ \
|
||||
volatile u64 *__ptr = (volatile u64 *)(ptr); \
|
||||
asm volatile(lock "cmpxchgq %2,%1" \
|
||||
: "=a" (__ret), "+m" (*__ptr) \
|
||||
: "r" (__new), "0" (__old) \
|
||||
: "memory"); \
|
||||
break; \
|
||||
} \
|
||||
default: \
|
||||
__cmpxchg_wrong_size(); \
|
||||
} \
|
||||
__ret; \
|
||||
})
|
||||
|
||||
#define __cmpxchg(ptr, old, new, size) \
|
||||
__raw_cmpxchg((ptr), (old), (new), (size), LOCK_PREFIX)
|
||||
|
||||
#define cmpxchg(ptr, old, new) \
|
||||
__cmpxchg(ptr, old, new, sizeof(*(ptr)))
|
||||
|
||||
|
||||
#endif /* TOOLS_ASM_X86_CMPXCHG_H */
|
|
@ -63,6 +63,7 @@ FEATURE_TESTS_BASIC := \
|
|||
lzma \
|
||||
get_cpuid \
|
||||
bpf \
|
||||
sched_getcpu \
|
||||
sdt
|
||||
|
||||
# FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list
|
||||
|
|
|
@ -48,12 +48,13 @@ FILES= \
|
|||
test-get_cpuid.bin \
|
||||
test-sdt.bin \
|
||||
test-cxx.bin \
|
||||
test-jvmti.bin
|
||||
test-jvmti.bin \
|
||||
test-sched_getcpu.bin
|
||||
|
||||
FILES := $(addprefix $(OUTPUT),$(FILES))
|
||||
|
||||
CC := $(CROSS_COMPILE)gcc -MD
|
||||
CXX := $(CROSS_COMPILE)g++ -MD
|
||||
CC ?= $(CROSS_COMPILE)gcc -MD
|
||||
CXX ?= $(CROSS_COMPILE)g++ -MD
|
||||
PKG_CONFIG := $(CROSS_COMPILE)pkg-config
|
||||
LLVM_CONFIG ?= llvm-config
|
||||
|
||||
|
@ -91,6 +92,9 @@ $(OUTPUT)test-libelf.bin:
|
|||
$(OUTPUT)test-glibc.bin:
|
||||
$(BUILD)
|
||||
|
||||
$(OUTPUT)test-sched_getcpu.bin:
|
||||
$(BUILD)
|
||||
|
||||
DWARFLIBS := -ldw
|
||||
ifeq ($(findstring -static,${LDFLAGS}),-static)
|
||||
DWARFLIBS += -lelf -lebl -lz -llzma -lbz2
|
||||
|
|
|
@ -117,6 +117,10 @@
|
|||
# include "test-pthread-attr-setaffinity-np.c"
|
||||
#undef main
|
||||
|
||||
#define main main_test_sched_getcpu
|
||||
# include "test-sched_getcpu.c"
|
||||
#undef main
|
||||
|
||||
# if 0
|
||||
/*
|
||||
* Disable libbabeltrace check for test-all, because the requested
|
||||
|
@ -182,6 +186,7 @@ int main(int argc, char *argv[])
|
|||
main_test_get_cpuid();
|
||||
main_test_bpf();
|
||||
main_test_libcrypto();
|
||||
main_test_sched_getcpu();
|
||||
main_test_sdt();
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
#define _GNU_SOURCE
|
||||
#include <sched.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return sched_getcpu();
|
||||
}
|
|
@ -60,4 +60,12 @@ static inline int atomic_dec_and_test(atomic_t *v)
|
|||
return __sync_sub_and_fetch(&v->counter, 1) == 0;
|
||||
}
|
||||
|
||||
#define cmpxchg(ptr, oldval, newval) \
|
||||
__sync_val_compare_and_swap(ptr, oldval, newval)
|
||||
|
||||
static inline int atomic_cmpxchg(atomic_t *v, int oldval, int newval)
|
||||
{
|
||||
return cmpxchg(&(v)->counter, oldval, newval);
|
||||
}
|
||||
|
||||
#endif /* __TOOLS_ASM_GENERIC_ATOMIC_H */
|
||||
|
|
|
@ -3,4 +3,10 @@
|
|||
|
||||
#include <asm/atomic.h>
|
||||
|
||||
/* atomic_cmpxchg_relaxed */
|
||||
#ifndef atomic_cmpxchg_relaxed
|
||||
#define atomic_cmpxchg_relaxed atomic_cmpxchg
|
||||
#define atomic_cmpxchg_release atomic_cmpxchg
|
||||
#endif /* atomic_cmpxchg_relaxed */
|
||||
|
||||
#endif /* __TOOLS_LINUX_ATOMIC_H */
|
||||
|
|
|
@ -12,3 +12,7 @@
|
|||
#if GCC_VERSION >= 70000 && !defined(__CHECKER__)
|
||||
# define __fallthrough __attribute__ ((fallthrough))
|
||||
#endif
|
||||
|
||||
#if GCC_VERSION >= 40300
|
||||
# define __compiletime_error(message) __attribute__((error(message)))
|
||||
#endif /* GCC_VERSION >= 40300 */
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
#include <linux/compiler-gcc.h>
|
||||
#endif
|
||||
|
||||
#ifndef __compiletime_error
|
||||
# define __compiletime_error(message)
|
||||
#endif
|
||||
|
||||
/* Optimization barrier */
|
||||
/* The "volatile" is due to gcc bugs */
|
||||
#define barrier() __asm__ __volatile__("": : :"memory")
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
#include <stddef.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifndef UINT_MAX
|
||||
#define UINT_MAX (~0U)
|
||||
#endif
|
||||
|
||||
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
|
||||
|
||||
#define PERF_ALIGN(x, a) __PERF_ALIGN_MASK(x, (typeof(x))(a)-1)
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
#ifndef _TOOLS_LINUX_REFCOUNT_H
|
||||
#define _TOOLS_LINUX_REFCOUNT_H
|
||||
|
||||
/*
|
||||
* Variant of atomic_t specialized for reference counts.
|
||||
*
|
||||
* The interface matches the atomic_t interface (to aid in porting) but only
|
||||
* provides the few functions one should use for reference counting.
|
||||
*
|
||||
* It differs in that the counter saturates at UINT_MAX and will not move once
|
||||
* there. This avoids wrapping the counter and causing 'spurious'
|
||||
* use-after-free issues.
|
||||
*
|
||||
* Memory ordering rules are slightly relaxed wrt regular atomic_t functions
|
||||
* and provide only what is strictly required for refcounts.
|
||||
*
|
||||
* The increments are fully relaxed; these will not provide ordering. The
|
||||
* rationale is that whatever is used to obtain the object we're increasing the
|
||||
* reference count on will provide the ordering. For locked data structures,
|
||||
* its the lock acquire, for RCU/lockless data structures its the dependent
|
||||
* load.
|
||||
*
|
||||
* Do note that inc_not_zero() provides a control dependency which will order
|
||||
* future stores against the inc, this ensures we'll never modify the object
|
||||
* if we did not in fact acquire a reference.
|
||||
*
|
||||
* The decrements will provide release order, such that all the prior loads and
|
||||
* stores will be issued before, it also provides a control dependency, which
|
||||
* will order us against the subsequent free().
|
||||
*
|
||||
* The control dependency is against the load of the cmpxchg (ll/sc) that
|
||||
* succeeded. This means the stores aren't fully ordered, but this is fine
|
||||
* because the 1->0 transition indicates no concurrency.
|
||||
*
|
||||
* Note that the allocator is responsible for ordering things between free()
|
||||
* and alloc().
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define REFCOUNT_WARN(cond, str) (void)(cond)
|
||||
#define __refcount_check
|
||||
#else
|
||||
#define REFCOUNT_WARN(cond, str) BUG_ON(cond)
|
||||
#define __refcount_check __must_check
|
||||
#endif
|
||||
|
||||
typedef struct refcount_struct {
|
||||
atomic_t refs;
|
||||
} refcount_t;
|
||||
|
||||
#define REFCOUNT_INIT(n) { .refs = ATOMIC_INIT(n), }
|
||||
|
||||
static inline void refcount_set(refcount_t *r, unsigned int n)
|
||||
{
|
||||
atomic_set(&r->refs, n);
|
||||
}
|
||||
|
||||
static inline unsigned int refcount_read(const refcount_t *r)
|
||||
{
|
||||
return atomic_read(&r->refs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Similar to atomic_inc_not_zero(), will saturate at UINT_MAX and WARN.
|
||||
*
|
||||
* Provides no memory ordering, it is assumed the caller has guaranteed the
|
||||
* object memory to be stable (RCU, etc.). It does provide a control dependency
|
||||
* and thereby orders future stores. See the comment on top.
|
||||
*/
|
||||
static inline __refcount_check
|
||||
bool refcount_inc_not_zero(refcount_t *r)
|
||||
{
|
||||
unsigned int old, new, val = atomic_read(&r->refs);
|
||||
|
||||
for (;;) {
|
||||
new = val + 1;
|
||||
|
||||
if (!val)
|
||||
return false;
|
||||
|
||||
if (unlikely(!new))
|
||||
return true;
|
||||
|
||||
old = atomic_cmpxchg_relaxed(&r->refs, val, new);
|
||||
if (old == val)
|
||||
break;
|
||||
|
||||
val = old;
|
||||
}
|
||||
|
||||
REFCOUNT_WARN(new == UINT_MAX, "refcount_t: saturated; leaking memory.\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Similar to atomic_inc(), will saturate at UINT_MAX and WARN.
|
||||
*
|
||||
* Provides no memory ordering, it is assumed the caller already has a
|
||||
* reference on the object, will WARN when this is not so.
|
||||
*/
|
||||
static inline void refcount_inc(refcount_t *r)
|
||||
{
|
||||
REFCOUNT_WARN(!refcount_inc_not_zero(r), "refcount_t: increment on 0; use-after-free.\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Similar to atomic_dec_and_test(), it will WARN on underflow and fail to
|
||||
* decrement when saturated at UINT_MAX.
|
||||
*
|
||||
* Provides release memory ordering, such that prior loads and stores are done
|
||||
* before, and provides a control dependency such that free() must come after.
|
||||
* See the comment on top.
|
||||
*/
|
||||
static inline __refcount_check
|
||||
bool refcount_sub_and_test(unsigned int i, refcount_t *r)
|
||||
{
|
||||
unsigned int old, new, val = atomic_read(&r->refs);
|
||||
|
||||
for (;;) {
|
||||
if (unlikely(val == UINT_MAX))
|
||||
return false;
|
||||
|
||||
new = val - i;
|
||||
if (new > val) {
|
||||
REFCOUNT_WARN(new > val, "refcount_t: underflow; use-after-free.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
old = atomic_cmpxchg_release(&r->refs, val, new);
|
||||
if (old == val)
|
||||
break;
|
||||
|
||||
val = old;
|
||||
}
|
||||
|
||||
return !new;
|
||||
}
|
||||
|
||||
static inline __refcount_check
|
||||
bool refcount_dec_and_test(refcount_t *r)
|
||||
{
|
||||
return refcount_sub_and_test(1, r);
|
||||
}
|
||||
|
||||
|
||||
#endif /* _ATOMIC_LINUX_REFCOUNT_H */
|
|
@ -30,6 +30,24 @@ OPTIONS
|
|||
--verbose=::
|
||||
Verbosity level.
|
||||
|
||||
-p::
|
||||
--pid=::
|
||||
Trace on existing process id (comma separated list).
|
||||
|
||||
-a::
|
||||
--all-cpus::
|
||||
Force system-wide collection. Scripts run without a <command>
|
||||
normally use -a by default, while scripts run with a <command>
|
||||
normally don't - this option allows the latter to be run in
|
||||
system-wide mode.
|
||||
|
||||
-C::
|
||||
--cpu=::
|
||||
Only trace for the list of CPUs provided. Multiple CPUs can
|
||||
be provided as a comma separated list with no space like: 0,1.
|
||||
Ranges of CPUs are specified with -: 0-2.
|
||||
Default is to trace on all online CPUs.
|
||||
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
|
|
|
@ -80,6 +80,7 @@ OPTIONS
|
|||
- pid: command and tid of the task
|
||||
- dso: name of library or module executed at the time of sample
|
||||
- symbol: name of function executed at the time of sample
|
||||
- symbol_size: size of function executed at the time of sample
|
||||
- parent: name of function matched to the parent regex filter. Unmatched
|
||||
entries are displayed as "[other]".
|
||||
- cpu: cpu number the task ran at the time of sample
|
||||
|
|
|
@ -12,6 +12,7 @@ tools/arch/sparc/include/asm/barrier_32.h
|
|||
tools/arch/sparc/include/asm/barrier_64.h
|
||||
tools/arch/tile/include/asm/barrier.h
|
||||
tools/arch/x86/include/asm/barrier.h
|
||||
tools/arch/x86/include/asm/cmpxchg.h
|
||||
tools/arch/x86/include/asm/cpufeatures.h
|
||||
tools/arch/x86/include/asm/disabled-features.h
|
||||
tools/arch/x86/include/asm/required-features.h
|
||||
|
@ -78,6 +79,7 @@ tools/include/uapi/linux/perf_event.h
|
|||
tools/include/linux/poison.h
|
||||
tools/include/linux/rbtree.h
|
||||
tools/include/linux/rbtree_augmented.h
|
||||
tools/include/linux/refcount.h
|
||||
tools/include/linux/string.h
|
||||
tools/include/linux/stringify.h
|
||||
tools/include/linux/types.h
|
||||
|
|
|
@ -317,6 +317,10 @@ ifdef NO_DWARF
|
|||
NO_LIBDW_DWARF_UNWIND := 1
|
||||
endif
|
||||
|
||||
ifeq ($(feature-sched_getcpu), 1)
|
||||
CFLAGS += -DHAVE_SCHED_GETCPU_SUPPORT
|
||||
endif
|
||||
|
||||
ifndef NO_LIBELF
|
||||
CFLAGS += -DHAVE_LIBELF_SUPPORT
|
||||
EXTLIBS += -lelf
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
*/
|
||||
|
||||
/* For the CLR_() macros */
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
|
||||
/* For the CLR_() macros */
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <signal.h>
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
*/
|
||||
|
||||
/* For the CLR_() macros */
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <signal.h>
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
|
||||
/* For the CLR_() macros */
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <signal.h>
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
*/
|
||||
|
||||
/* For the CLR_() macros */
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <signal.h>
|
||||
|
|
|
@ -88,13 +88,11 @@ futex_cmp_requeue(u_int32_t *uaddr, u_int32_t val, u_int32_t *uaddr2, int nr_wak
|
|||
|
||||
#ifndef HAVE_PTHREAD_ATTR_SETAFFINITY_NP
|
||||
#include <pthread.h>
|
||||
static inline int pthread_attr_setaffinity_np(pthread_attr_t *attr,
|
||||
size_t cpusetsize,
|
||||
cpu_set_t *cpuset)
|
||||
#include <linux/compiler.h>
|
||||
static inline int pthread_attr_setaffinity_np(pthread_attr_t *attr __maybe_unused,
|
||||
size_t cpusetsize __maybe_unused,
|
||||
cpu_set_t *cpuset __maybe_unused)
|
||||
{
|
||||
attr = attr;
|
||||
cpusetsize = cpusetsize;
|
||||
cpuset = cpuset;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -187,7 +187,8 @@ static const struct option options[] = {
|
|||
OPT_INCR ('d', "show_details" , &p0.show_details, "Show details"),
|
||||
OPT_INCR ('a', "all" , &p0.run_all, "Run all tests in the suite"),
|
||||
OPT_INTEGER('H', "thp" , &p0.thp, "MADV_NOHUGEPAGE < 0 < MADV_HUGEPAGE"),
|
||||
OPT_BOOLEAN('c', "show_convergence", &p0.show_convergence, "show convergence details"),
|
||||
OPT_BOOLEAN('c', "show_convergence", &p0.show_convergence, "show convergence details, "
|
||||
"convergence is reached when each process (all its threads) is running on a single NUMA node."),
|
||||
OPT_BOOLEAN('m', "measure_convergence", &p0.measure_convergence, "measure convergence latency"),
|
||||
OPT_BOOLEAN('q', "quiet" , &p0.show_quiet, "quiet mode"),
|
||||
OPT_BOOLEAN('S', "serialize-startup", &p0.serialize_startup,"serialize thread startup"),
|
||||
|
|
|
@ -11,11 +11,13 @@
|
|||
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "evlist.h"
|
||||
#include "target.h"
|
||||
#include "cpumap.h"
|
||||
#include "thread_map.h"
|
||||
#include "util/config.h"
|
||||
|
||||
|
@ -50,11 +52,12 @@ static void ftrace__workload_exec_failed_signal(int signo __maybe_unused,
|
|||
done = true;
|
||||
}
|
||||
|
||||
static int write_tracing_file(const char *name, const char *val)
|
||||
static int __write_tracing_file(const char *name, const char *val, bool append)
|
||||
{
|
||||
char *file;
|
||||
int fd, ret = -1;
|
||||
ssize_t size = strlen(val);
|
||||
int flags = O_WRONLY;
|
||||
|
||||
file = get_tracing_file(name);
|
||||
if (!file) {
|
||||
|
@ -62,7 +65,12 @@ static int write_tracing_file(const char *name, const char *val)
|
|||
return -1;
|
||||
}
|
||||
|
||||
fd = open(file, O_WRONLY);
|
||||
if (append)
|
||||
flags |= O_APPEND;
|
||||
else
|
||||
flags |= O_TRUNC;
|
||||
|
||||
fd = open(file, flags);
|
||||
if (fd < 0) {
|
||||
pr_debug("cannot open tracing file: %s\n", name);
|
||||
goto out;
|
||||
|
@ -79,6 +87,18 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int write_tracing_file(const char *name, const char *val)
|
||||
{
|
||||
return __write_tracing_file(name, val, false);
|
||||
}
|
||||
|
||||
static int append_tracing_file(const char *name, const char *val)
|
||||
{
|
||||
return __write_tracing_file(name, val, true);
|
||||
}
|
||||
|
||||
static int reset_tracing_cpu(void);
|
||||
|
||||
static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused)
|
||||
{
|
||||
if (write_tracing_file("tracing_on", "0") < 0)
|
||||
|
@ -90,14 +110,78 @@ static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused)
|
|||
if (write_tracing_file("set_ftrace_pid", " ") < 0)
|
||||
return -1;
|
||||
|
||||
if (reset_tracing_cpu() < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_tracing_pid(struct perf_ftrace *ftrace)
|
||||
{
|
||||
int i;
|
||||
char buf[16];
|
||||
|
||||
if (target__has_cpu(&ftrace->target))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < thread_map__nr(ftrace->evlist->threads); i++) {
|
||||
scnprintf(buf, sizeof(buf), "%d",
|
||||
ftrace->evlist->threads->map[i]);
|
||||
if (append_tracing_file("set_ftrace_pid", buf) < 0)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_tracing_cpumask(struct cpu_map *cpumap)
|
||||
{
|
||||
char *cpumask;
|
||||
size_t mask_size;
|
||||
int ret;
|
||||
int last_cpu;
|
||||
|
||||
last_cpu = cpu_map__cpu(cpumap, cpumap->nr - 1);
|
||||
mask_size = (last_cpu + 3) / 4 + 1;
|
||||
mask_size += last_cpu / 32; /* ',' is needed for every 32th cpus */
|
||||
|
||||
cpumask = malloc(mask_size);
|
||||
if (cpumask == NULL) {
|
||||
pr_debug("failed to allocate cpu mask\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cpu_map__snprint_mask(cpumap, cpumask, mask_size);
|
||||
|
||||
ret = write_tracing_file("tracing_cpumask", cpumask);
|
||||
|
||||
free(cpumask);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_tracing_cpu(struct perf_ftrace *ftrace)
|
||||
{
|
||||
struct cpu_map *cpumap = ftrace->evlist->cpus;
|
||||
|
||||
if (!target__has_cpu(&ftrace->target))
|
||||
return 0;
|
||||
|
||||
return set_tracing_cpumask(cpumap);
|
||||
}
|
||||
|
||||
static int reset_tracing_cpu(void)
|
||||
{
|
||||
struct cpu_map *cpumap = cpu_map__new(NULL);
|
||||
int ret;
|
||||
|
||||
ret = set_tracing_cpumask(cpumap);
|
||||
cpu_map__put(cpumap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
|
||||
{
|
||||
char *trace_file;
|
||||
int trace_fd;
|
||||
char *trace_pid;
|
||||
char buf[4096];
|
||||
struct pollfd pollfd = {
|
||||
.events = POLLIN,
|
||||
|
@ -108,42 +192,43 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (argc < 1)
|
||||
return -1;
|
||||
|
||||
signal(SIGINT, sig_handler);
|
||||
signal(SIGUSR1, sig_handler);
|
||||
signal(SIGCHLD, sig_handler);
|
||||
signal(SIGPIPE, sig_handler);
|
||||
|
||||
reset_tracing_files(ftrace);
|
||||
if (reset_tracing_files(ftrace) < 0)
|
||||
goto out;
|
||||
|
||||
/* reset ftrace buffer */
|
||||
if (write_tracing_file("trace", "0") < 0)
|
||||
goto out;
|
||||
|
||||
if (perf_evlist__prepare_workload(ftrace->evlist, &ftrace->target,
|
||||
argv, false, ftrace__workload_exec_failed_signal) < 0)
|
||||
if (argc && perf_evlist__prepare_workload(ftrace->evlist,
|
||||
&ftrace->target, argv, false,
|
||||
ftrace__workload_exec_failed_signal) < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (set_tracing_pid(ftrace) < 0) {
|
||||
pr_err("failed to set ftrace pid\n");
|
||||
goto out_reset;
|
||||
}
|
||||
|
||||
if (set_tracing_cpu(ftrace) < 0) {
|
||||
pr_err("failed to set tracing cpumask\n");
|
||||
goto out_reset;
|
||||
}
|
||||
|
||||
if (write_tracing_file("current_tracer", ftrace->tracer) < 0) {
|
||||
pr_err("failed to set current_tracer to %s\n", ftrace->tracer);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (asprintf(&trace_pid, "%d", thread_map__pid(ftrace->evlist->threads, 0)) < 0) {
|
||||
pr_err("failed to allocate pid string\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (write_tracing_file("set_ftrace_pid", trace_pid) < 0) {
|
||||
pr_err("failed to set pid: %s\n", trace_pid);
|
||||
goto out_free_pid;
|
||||
goto out_reset;
|
||||
}
|
||||
|
||||
trace_file = get_tracing_file("trace_pipe");
|
||||
if (!trace_file) {
|
||||
pr_err("failed to open trace_pipe\n");
|
||||
goto out_free_pid;
|
||||
goto out_reset;
|
||||
}
|
||||
|
||||
trace_fd = open(trace_file, O_RDONLY);
|
||||
|
@ -152,7 +237,7 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
|
|||
|
||||
if (trace_fd < 0) {
|
||||
pr_err("failed to open trace_pipe\n");
|
||||
goto out_free_pid;
|
||||
goto out_reset;
|
||||
}
|
||||
|
||||
fcntl(trace_fd, F_SETFL, O_NONBLOCK);
|
||||
|
@ -163,6 +248,8 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
|
|||
goto out_close_fd;
|
||||
}
|
||||
|
||||
setup_pager();
|
||||
|
||||
perf_evlist__start_workload(ftrace->evlist);
|
||||
|
||||
while (!done) {
|
||||
|
@ -191,11 +278,9 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
|
|||
|
||||
out_close_fd:
|
||||
close(trace_fd);
|
||||
out_free_pid:
|
||||
free(trace_pid);
|
||||
out:
|
||||
out_reset:
|
||||
reset_tracing_files(ftrace);
|
||||
|
||||
out:
|
||||
return done ? 0 : -1;
|
||||
}
|
||||
|
||||
|
@ -227,15 +312,21 @@ int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused)
|
|||
.target = { .uid = UINT_MAX, },
|
||||
};
|
||||
const char * const ftrace_usage[] = {
|
||||
"perf ftrace [<options>] <command>",
|
||||
"perf ftrace [<options>] [<command>]",
|
||||
"perf ftrace [<options>] -- <command> [<options>]",
|
||||
NULL
|
||||
};
|
||||
const struct option ftrace_options[] = {
|
||||
OPT_STRING('t', "tracer", &ftrace.tracer, "tracer",
|
||||
"tracer to use: function_graph(default) or function"),
|
||||
OPT_STRING('p', "pid", &ftrace.target.pid, "pid",
|
||||
"trace on existing process id"),
|
||||
OPT_INCR('v', "verbose", &verbose,
|
||||
"be more verbose"),
|
||||
OPT_BOOLEAN('a', "all-cpus", &ftrace.target.system_wide,
|
||||
"system-wide collection from all CPUs"),
|
||||
OPT_STRING('C', "cpu", &ftrace.target.cpu_list, "cpu",
|
||||
"list of cpus to monitor"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
|
@ -245,9 +336,18 @@ int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused)
|
|||
|
||||
argc = parse_options(argc, argv, ftrace_options, ftrace_usage,
|
||||
PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
if (!argc)
|
||||
if (!argc && target__none(&ftrace.target))
|
||||
usage_with_options(ftrace_usage, ftrace_options);
|
||||
|
||||
ret = target__validate(&ftrace.target);
|
||||
if (ret) {
|
||||
char errbuf[512];
|
||||
|
||||
target__strerror(&ftrace.target, ret, errbuf, 512);
|
||||
pr_err("%s\n", errbuf);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ftrace.evlist = perf_evlist__new();
|
||||
if (ftrace.evlist == NULL)
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -146,6 +146,7 @@ static aggr_get_id_t aggr_get_id;
|
|||
static bool append_file;
|
||||
static const char *output_name;
|
||||
static int output_fd;
|
||||
static int print_free_counters_hint;
|
||||
|
||||
struct perf_stat {
|
||||
bool record;
|
||||
|
@ -1109,6 +1110,9 @@ static void printout(int id, int nr, struct perf_evsel *counter, double uval,
|
|||
counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
|
||||
csv_sep);
|
||||
|
||||
if (counter->supported)
|
||||
print_free_counters_hint = 1;
|
||||
|
||||
fprintf(stat_config.output, "%-*s%s",
|
||||
csv_output ? 0 : unit_width,
|
||||
counter->unit, csv_sep);
|
||||
|
@ -1477,6 +1481,13 @@ static void print_footer(void)
|
|||
avg_stats(&walltime_nsecs_stats));
|
||||
}
|
||||
fprintf(output, "\n\n");
|
||||
|
||||
if (print_free_counters_hint)
|
||||
fprintf(output,
|
||||
"Some events weren't counted. Try disabling the NMI watchdog:\n"
|
||||
" echo 0 > /proc/sys/kernel/nmi_watchdog\n"
|
||||
" perf stat ...\n"
|
||||
" echo 1 > /proc/sys/kernel/nmi_watchdog\n");
|
||||
}
|
||||
|
||||
static void print_counters(struct timespec *ts, int argc, const char **argv)
|
||||
|
@ -2339,6 +2350,35 @@ static int __cmd_report(int argc, const char **argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void setup_system_wide(int forks)
|
||||
{
|
||||
/*
|
||||
* Make system wide (-a) the default target if
|
||||
* no target was specified and one of following
|
||||
* conditions is met:
|
||||
*
|
||||
* - there's no workload specified
|
||||
* - there is workload specified but all requested
|
||||
* events are system wide events
|
||||
*/
|
||||
if (!target__none(&target))
|
||||
return;
|
||||
|
||||
if (!forks)
|
||||
target.system_wide = true;
|
||||
else {
|
||||
struct perf_evsel *counter;
|
||||
|
||||
evlist__for_each_entry(evsel_list, counter) {
|
||||
if (!counter->system_wide)
|
||||
return;
|
||||
}
|
||||
|
||||
if (evsel_list->nr_entries)
|
||||
target.system_wide = true;
|
||||
}
|
||||
}
|
||||
|
||||
int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
{
|
||||
const char * const stat_usage[] = {
|
||||
|
@ -2445,9 +2485,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
|
|||
} else if (big_num_opt == 0) /* User passed --no-big-num */
|
||||
big_num = false;
|
||||
|
||||
/* Make system wide (-a) the default target. */
|
||||
if (!argc && target__none(&target))
|
||||
target.system_wide = true;
|
||||
setup_system_wide(argc);
|
||||
|
||||
if (run_count < 0) {
|
||||
pr_err("Run count must be a positive number\n");
|
||||
|
|
|
@ -17,6 +17,7 @@ GenuineIntel-6-3A,v18,ivybridge,core
|
|||
GenuineIntel-6-3E,v19,ivytown,core
|
||||
GenuineIntel-6-2D,v20,jaketown,core
|
||||
GenuineIntel-6-57,v9,knightslanding,core
|
||||
GenuineIntel-6-85,v9,knightslanding,core
|
||||
GenuineIntel-6-1E,v2,nehalemep,core
|
||||
GenuineIntel-6-1F,v2,nehalemep,core
|
||||
GenuineIntel-6-1A,v2,nehalemep,core
|
||||
|
|
|
|
@ -66,7 +66,7 @@ static int process_event_cpus(struct perf_tool *tool __maybe_unused,
|
|||
TEST_ASSERT_VAL("wrong nr", map->nr == 2);
|
||||
TEST_ASSERT_VAL("wrong cpu", map->map[0] == 1);
|
||||
TEST_ASSERT_VAL("wrong cpu", map->map[1] == 256);
|
||||
TEST_ASSERT_VAL("wrong refcnt", atomic_read(&map->refcnt) == 1);
|
||||
TEST_ASSERT_VAL("wrong refcnt", refcount_read(&map->refcnt) == 1);
|
||||
cpu_map__put(map);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ int test__thread_map(int subtest __maybe_unused)
|
|||
thread_map__comm(map, 0) &&
|
||||
!strcmp(thread_map__comm(map, 0), NAME));
|
||||
TEST_ASSERT_VAL("wrong refcnt",
|
||||
atomic_read(&map->refcnt) == 1);
|
||||
refcount_read(&map->refcnt) == 1);
|
||||
thread_map__put(map);
|
||||
|
||||
/* test dummy pid */
|
||||
|
@ -44,7 +44,7 @@ int test__thread_map(int subtest __maybe_unused)
|
|||
thread_map__comm(map, 0) &&
|
||||
!strcmp(thread_map__comm(map, 0), "dummy"));
|
||||
TEST_ASSERT_VAL("wrong refcnt",
|
||||
atomic_read(&map->refcnt) == 1);
|
||||
refcount_read(&map->refcnt) == 1);
|
||||
thread_map__put(map);
|
||||
return 0;
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ static int process_event(struct perf_tool *tool __maybe_unused,
|
|||
thread_map__comm(threads, 0) &&
|
||||
!strcmp(thread_map__comm(threads, 0), NAME));
|
||||
TEST_ASSERT_VAL("wrong refcnt",
|
||||
atomic_read(&threads->refcnt) == 1);
|
||||
refcount_read(&threads->refcnt) == 1);
|
||||
thread_map__put(threads);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ int test__thread_mg_share(int subtest __maybe_unused)
|
|||
leader && t1 && t2 && t3 && other);
|
||||
|
||||
mg = leader->mg;
|
||||
TEST_ASSERT_EQUAL("wrong refcnt", atomic_read(&mg->refcnt), 4);
|
||||
TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&mg->refcnt), 4);
|
||||
|
||||
/* test the map groups pointer is shared */
|
||||
TEST_ASSERT_VAL("map groups don't match", mg == t1->mg);
|
||||
|
@ -71,25 +71,25 @@ int test__thread_mg_share(int subtest __maybe_unused)
|
|||
machine__remove_thread(machine, other_leader);
|
||||
|
||||
other_mg = other->mg;
|
||||
TEST_ASSERT_EQUAL("wrong refcnt", atomic_read(&other_mg->refcnt), 2);
|
||||
TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&other_mg->refcnt), 2);
|
||||
|
||||
TEST_ASSERT_VAL("map groups don't match", other_mg == other_leader->mg);
|
||||
|
||||
/* release thread group */
|
||||
thread__put(leader);
|
||||
TEST_ASSERT_EQUAL("wrong refcnt", atomic_read(&mg->refcnt), 3);
|
||||
TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&mg->refcnt), 3);
|
||||
|
||||
thread__put(t1);
|
||||
TEST_ASSERT_EQUAL("wrong refcnt", atomic_read(&mg->refcnt), 2);
|
||||
TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&mg->refcnt), 2);
|
||||
|
||||
thread__put(t2);
|
||||
TEST_ASSERT_EQUAL("wrong refcnt", atomic_read(&mg->refcnt), 1);
|
||||
TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&mg->refcnt), 1);
|
||||
|
||||
thread__put(t3);
|
||||
|
||||
/* release other group */
|
||||
thread__put(other_leader);
|
||||
TEST_ASSERT_EQUAL("wrong refcnt", atomic_read(&other_mg->refcnt), 1);
|
||||
TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&other_mg->refcnt), 1);
|
||||
|
||||
thread__put(other);
|
||||
|
||||
|
|
|
@ -127,19 +127,19 @@ static int add_cgroup(struct perf_evlist *evlist, char *str)
|
|||
goto found;
|
||||
n++;
|
||||
}
|
||||
if (atomic_read(&cgrp->refcnt) == 0)
|
||||
if (refcount_read(&cgrp->refcnt) == 0)
|
||||
free(cgrp);
|
||||
|
||||
return -1;
|
||||
found:
|
||||
atomic_inc(&cgrp->refcnt);
|
||||
refcount_inc(&cgrp->refcnt);
|
||||
counter->cgrp = cgrp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void close_cgroup(struct cgroup_sel *cgrp)
|
||||
{
|
||||
if (cgrp && atomic_dec_and_test(&cgrp->refcnt)) {
|
||||
if (cgrp && refcount_dec_and_test(&cgrp->refcnt)) {
|
||||
close(cgrp->fd);
|
||||
zfree(&cgrp->name);
|
||||
free(cgrp);
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
#ifndef __CGROUP_H__
|
||||
#define __CGROUP_H__
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/refcount.h>
|
||||
|
||||
struct option;
|
||||
|
||||
struct cgroup_sel {
|
||||
char *name;
|
||||
int fd;
|
||||
atomic_t refcnt;
|
||||
refcount_t refcnt;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -3,10 +3,4 @@
|
|||
|
||||
unsigned long perf_event_open_cloexec_flag(void);
|
||||
|
||||
#ifdef __GLIBC_PREREQ
|
||||
#if !__GLIBC_PREREQ(2, 6) && !defined(__UCLIBC__)
|
||||
int sched_getcpu(void) __THROW;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* __PERF_CLOEXEC_H */
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
#include "util.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/refcount.h>
|
||||
|
||||
struct comm_str {
|
||||
char *str;
|
||||
struct rb_node rb_node;
|
||||
atomic_t refcnt;
|
||||
refcount_t refcnt;
|
||||
};
|
||||
|
||||
/* Should perhaps be moved to struct machine */
|
||||
|
@ -16,13 +16,13 @@ static struct rb_root comm_str_root;
|
|||
static struct comm_str *comm_str__get(struct comm_str *cs)
|
||||
{
|
||||
if (cs)
|
||||
atomic_inc(&cs->refcnt);
|
||||
refcount_inc(&cs->refcnt);
|
||||
return cs;
|
||||
}
|
||||
|
||||
static void comm_str__put(struct comm_str *cs)
|
||||
{
|
||||
if (cs && atomic_dec_and_test(&cs->refcnt)) {
|
||||
if (cs && refcount_dec_and_test(&cs->refcnt)) {
|
||||
rb_erase(&cs->rb_node, &comm_str_root);
|
||||
zfree(&cs->str);
|
||||
free(cs);
|
||||
|
@ -43,7 +43,7 @@ static struct comm_str *comm_str__alloc(const char *str)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
atomic_set(&cs->refcnt, 0);
|
||||
refcount_set(&cs->refcnt, 1);
|
||||
|
||||
return cs;
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root)
|
|||
|
||||
cmp = strcmp(str, iter->str);
|
||||
if (!cmp)
|
||||
return iter;
|
||||
return comm_str__get(iter);
|
||||
|
||||
if (cmp < 0)
|
||||
p = &(*p)->rb_left;
|
||||
|
@ -95,8 +95,6 @@ struct comm *comm__new(const char *str, u64 timestamp, bool exec)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
comm_str__get(comm->comm_str);
|
||||
|
||||
return comm;
|
||||
}
|
||||
|
||||
|
@ -108,7 +106,6 @@ int comm__override(struct comm *comm, const char *str, u64 timestamp, bool exec)
|
|||
if (!new)
|
||||
return -ENOMEM;
|
||||
|
||||
comm_str__get(new);
|
||||
comm_str__put(old);
|
||||
comm->comm_str = new;
|
||||
comm->start = timestamp;
|
||||
|
|
|
@ -29,7 +29,7 @@ static struct cpu_map *cpu_map__default_new(void)
|
|||
cpus->map[i] = i;
|
||||
|
||||
cpus->nr = nr_cpus;
|
||||
atomic_set(&cpus->refcnt, 1);
|
||||
refcount_set(&cpus->refcnt, 1);
|
||||
}
|
||||
|
||||
return cpus;
|
||||
|
@ -43,7 +43,7 @@ static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus)
|
|||
if (cpus != NULL) {
|
||||
cpus->nr = nr_cpus;
|
||||
memcpy(cpus->map, tmp_cpus, payload_size);
|
||||
atomic_set(&cpus->refcnt, 1);
|
||||
refcount_set(&cpus->refcnt, 1);
|
||||
}
|
||||
|
||||
return cpus;
|
||||
|
@ -252,7 +252,7 @@ struct cpu_map *cpu_map__dummy_new(void)
|
|||
if (cpus != NULL) {
|
||||
cpus->nr = 1;
|
||||
cpus->map[0] = -1;
|
||||
atomic_set(&cpus->refcnt, 1);
|
||||
refcount_set(&cpus->refcnt, 1);
|
||||
}
|
||||
|
||||
return cpus;
|
||||
|
@ -269,7 +269,7 @@ struct cpu_map *cpu_map__empty_new(int nr)
|
|||
for (i = 0; i < nr; i++)
|
||||
cpus->map[i] = -1;
|
||||
|
||||
atomic_set(&cpus->refcnt, 1);
|
||||
refcount_set(&cpus->refcnt, 1);
|
||||
}
|
||||
|
||||
return cpus;
|
||||
|
@ -278,7 +278,7 @@ struct cpu_map *cpu_map__empty_new(int nr)
|
|||
static void cpu_map__delete(struct cpu_map *map)
|
||||
{
|
||||
if (map) {
|
||||
WARN_ONCE(atomic_read(&map->refcnt) != 0,
|
||||
WARN_ONCE(refcount_read(&map->refcnt) != 0,
|
||||
"cpu_map refcnt unbalanced\n");
|
||||
free(map);
|
||||
}
|
||||
|
@ -287,13 +287,13 @@ static void cpu_map__delete(struct cpu_map *map)
|
|||
struct cpu_map *cpu_map__get(struct cpu_map *map)
|
||||
{
|
||||
if (map)
|
||||
atomic_inc(&map->refcnt);
|
||||
refcount_inc(&map->refcnt);
|
||||
return map;
|
||||
}
|
||||
|
||||
void cpu_map__put(struct cpu_map *map)
|
||||
{
|
||||
if (map && atomic_dec_and_test(&map->refcnt))
|
||||
if (map && refcount_dec_and_test(&map->refcnt))
|
||||
cpu_map__delete(map);
|
||||
}
|
||||
|
||||
|
@ -357,7 +357,7 @@ int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res,
|
|||
/* ensure we process id in increasing order */
|
||||
qsort(c->map, c->nr, sizeof(int), cmp_ids);
|
||||
|
||||
atomic_set(&c->refcnt, 1);
|
||||
refcount_set(&c->refcnt, 1);
|
||||
*res = c;
|
||||
return 0;
|
||||
}
|
||||
|
@ -673,3 +673,49 @@ size_t cpu_map__snprint(struct cpu_map *map, char *buf, size_t size)
|
|||
pr_debug("cpumask list: %s\n", buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char hex_char(unsigned char val)
|
||||
{
|
||||
if (val < 10)
|
||||
return val + '0';
|
||||
if (val < 16)
|
||||
return val - 10 + 'a';
|
||||
return '?';
|
||||
}
|
||||
|
||||
size_t cpu_map__snprint_mask(struct cpu_map *map, char *buf, size_t size)
|
||||
{
|
||||
int i, cpu;
|
||||
char *ptr = buf;
|
||||
unsigned char *bitmap;
|
||||
int last_cpu = cpu_map__cpu(map, map->nr - 1);
|
||||
|
||||
bitmap = zalloc((last_cpu + 7) / 8);
|
||||
if (bitmap == NULL) {
|
||||
buf[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < map->nr; i++) {
|
||||
cpu = cpu_map__cpu(map, i);
|
||||
bitmap[cpu / 8] |= 1 << (cpu % 8);
|
||||
}
|
||||
|
||||
for (cpu = last_cpu / 4 * 4; cpu >= 0; cpu -= 4) {
|
||||
unsigned char bits = bitmap[cpu / 8];
|
||||
|
||||
if (cpu % 8)
|
||||
bits >>= 4;
|
||||
else
|
||||
bits &= 0xf;
|
||||
|
||||
*ptr++ = hex_char(bits);
|
||||
if ((cpu % 32) == 0 && cpu > 0)
|
||||
*ptr++ = ',';
|
||||
}
|
||||
*ptr = '\0';
|
||||
free(bitmap);
|
||||
|
||||
buf[size - 1] = '\0';
|
||||
return ptr - buf;
|
||||
}
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/refcount.h>
|
||||
|
||||
#include "perf.h"
|
||||
#include "util/debug.h"
|
||||
|
||||
struct cpu_map {
|
||||
atomic_t refcnt;
|
||||
refcount_t refcnt;
|
||||
int nr;
|
||||
int map[];
|
||||
};
|
||||
|
@ -20,6 +20,7 @@ struct cpu_map *cpu_map__dummy_new(void);
|
|||
struct cpu_map *cpu_map__new_data(struct cpu_map_data *data);
|
||||
struct cpu_map *cpu_map__read(FILE *file);
|
||||
size_t cpu_map__snprint(struct cpu_map *map, char *buf, size_t size);
|
||||
size_t cpu_map__snprint_mask(struct cpu_map *map, char *buf, size_t size);
|
||||
size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
|
||||
int cpu_map__get_socket_id(int cpu);
|
||||
int cpu_map__get_socket(struct cpu_map *map, int idx, void *data);
|
||||
|
|
|
@ -1109,7 +1109,7 @@ struct dso *dso__new(const char *name)
|
|||
INIT_LIST_HEAD(&dso->node);
|
||||
INIT_LIST_HEAD(&dso->data.open_entry);
|
||||
pthread_mutex_init(&dso->lock, NULL);
|
||||
atomic_set(&dso->refcnt, 1);
|
||||
refcount_set(&dso->refcnt, 1);
|
||||
}
|
||||
|
||||
return dso;
|
||||
|
@ -1147,13 +1147,13 @@ void dso__delete(struct dso *dso)
|
|||
struct dso *dso__get(struct dso *dso)
|
||||
{
|
||||
if (dso)
|
||||
atomic_inc(&dso->refcnt);
|
||||
refcount_inc(&dso->refcnt);
|
||||
return dso;
|
||||
}
|
||||
|
||||
void dso__put(struct dso *dso)
|
||||
{
|
||||
if (dso && atomic_dec_and_test(&dso->refcnt))
|
||||
if (dso && refcount_dec_and_test(&dso->refcnt))
|
||||
dso__delete(dso);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __PERF_DSO
|
||||
#define __PERF_DSO
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/refcount.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <sys/types.h>
|
||||
|
@ -187,7 +187,7 @@ struct dso {
|
|||
void *priv;
|
||||
u64 db_id;
|
||||
};
|
||||
atomic_t refcnt;
|
||||
refcount_t refcnt;
|
||||
char name[0];
|
||||
};
|
||||
|
||||
|
|
|
@ -777,7 +777,7 @@ union perf_event *perf_mmap__read_forward(struct perf_mmap *md, bool check_messu
|
|||
/*
|
||||
* Check if event was unmapped due to a POLLHUP/POLLERR.
|
||||
*/
|
||||
if (!atomic_read(&md->refcnt))
|
||||
if (!refcount_read(&md->refcnt))
|
||||
return NULL;
|
||||
|
||||
head = perf_mmap__read_head(md);
|
||||
|
@ -794,7 +794,7 @@ perf_mmap__read_backward(struct perf_mmap *md)
|
|||
/*
|
||||
* Check if event was unmapped due to a POLLHUP/POLLERR.
|
||||
*/
|
||||
if (!atomic_read(&md->refcnt))
|
||||
if (!refcount_read(&md->refcnt))
|
||||
return NULL;
|
||||
|
||||
head = perf_mmap__read_head(md);
|
||||
|
@ -856,7 +856,7 @@ void perf_mmap__read_catchup(struct perf_mmap *md)
|
|||
{
|
||||
u64 head;
|
||||
|
||||
if (!atomic_read(&md->refcnt))
|
||||
if (!refcount_read(&md->refcnt))
|
||||
return;
|
||||
|
||||
head = perf_mmap__read_head(md);
|
||||
|
@ -875,14 +875,14 @@ static bool perf_mmap__empty(struct perf_mmap *md)
|
|||
|
||||
static void perf_mmap__get(struct perf_mmap *map)
|
||||
{
|
||||
atomic_inc(&map->refcnt);
|
||||
refcount_inc(&map->refcnt);
|
||||
}
|
||||
|
||||
static void perf_mmap__put(struct perf_mmap *md)
|
||||
{
|
||||
BUG_ON(md->base && atomic_read(&md->refcnt) == 0);
|
||||
BUG_ON(md->base && refcount_read(&md->refcnt) == 0);
|
||||
|
||||
if (atomic_dec_and_test(&md->refcnt))
|
||||
if (refcount_dec_and_test(&md->refcnt))
|
||||
perf_mmap__munmap(md);
|
||||
}
|
||||
|
||||
|
@ -894,7 +894,7 @@ void perf_mmap__consume(struct perf_mmap *md, bool overwrite)
|
|||
perf_mmap__write_tail(md, old);
|
||||
}
|
||||
|
||||
if (atomic_read(&md->refcnt) == 1 && perf_mmap__empty(md))
|
||||
if (refcount_read(&md->refcnt) == 1 && perf_mmap__empty(md))
|
||||
perf_mmap__put(md);
|
||||
}
|
||||
|
||||
|
@ -937,7 +937,7 @@ static void perf_mmap__munmap(struct perf_mmap *map)
|
|||
munmap(map->base, perf_mmap__mmap_len(map));
|
||||
map->base = NULL;
|
||||
map->fd = -1;
|
||||
atomic_set(&map->refcnt, 0);
|
||||
refcount_set(&map->refcnt, 0);
|
||||
}
|
||||
auxtrace_mmap__munmap(&map->auxtrace_mmap);
|
||||
}
|
||||
|
@ -974,8 +974,19 @@ static struct perf_mmap *perf_evlist__alloc_mmap(struct perf_evlist *evlist)
|
|||
if (!map)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < evlist->nr_mmaps; i++)
|
||||
for (i = 0; i < evlist->nr_mmaps; i++) {
|
||||
map[i].fd = -1;
|
||||
/*
|
||||
* When the perf_mmap() call is made we grab one refcount, plus
|
||||
* one extra to let perf_evlist__mmap_consume() get the last
|
||||
* events after all real references (perf_mmap__get()) are
|
||||
* dropped.
|
||||
*
|
||||
* Each PERF_EVENT_IOC_SET_OUTPUT points to this mmap and
|
||||
* thus does perf_mmap__get() on it.
|
||||
*/
|
||||
refcount_set(&map[i].refcnt, 0);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
|
@ -1001,7 +1012,7 @@ static int perf_mmap__mmap(struct perf_mmap *map,
|
|||
* evlist layer can't just drop it when filtering events in
|
||||
* perf_evlist__filter_pollfd().
|
||||
*/
|
||||
atomic_set(&map->refcnt, 2);
|
||||
refcount_set(&map->refcnt, 2);
|
||||
map->prev = 0;
|
||||
map->mask = mp->mask;
|
||||
map->base = mmap(NULL, perf_mmap__mmap_len(map), mp->prot,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __PERF_EVLIST_H
|
||||
#define __PERF_EVLIST_H 1
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/refcount.h>
|
||||
#include <linux/list.h>
|
||||
#include <api/fd/array.h>
|
||||
#include <stdio.h>
|
||||
|
@ -29,7 +29,7 @@ struct perf_mmap {
|
|||
void *base;
|
||||
int mask;
|
||||
int fd;
|
||||
atomic_t refcnt;
|
||||
refcount_t refcnt;
|
||||
u64 prev;
|
||||
struct auxtrace_mmap auxtrace_mmap;
|
||||
char event_copy[PERF_SAMPLE_MAX_SIZE] __attribute__((aligned(8)));
|
||||
|
|
|
@ -57,6 +57,7 @@ enum hist_column {
|
|||
HISTC_SRCLINE_FROM,
|
||||
HISTC_SRCLINE_TO,
|
||||
HISTC_TRACE,
|
||||
HISTC_SYM_SIZE,
|
||||
HISTC_NR_COLS, /* Last entry */
|
||||
};
|
||||
|
||||
|
|
|
@ -39,6 +39,8 @@ static void intel_pt_insn_decoder(struct insn *insn,
|
|||
enum intel_pt_insn_branch branch = INTEL_PT_BR_NO_BRANCH;
|
||||
int ext;
|
||||
|
||||
intel_pt_insn->rel = 0;
|
||||
|
||||
if (insn_is_avx(insn)) {
|
||||
intel_pt_insn->op = INTEL_PT_OP_OTHER;
|
||||
intel_pt_insn->branch = INTEL_PT_BR_NO_BRANCH;
|
||||
|
|
|
@ -1439,7 +1439,7 @@ static void __machine__remove_thread(struct machine *machine, struct thread *th,
|
|||
if (machine->last_match == th)
|
||||
machine->last_match = NULL;
|
||||
|
||||
BUG_ON(atomic_read(&th->refcnt) == 0);
|
||||
BUG_ON(refcount_read(&th->refcnt) == 0);
|
||||
if (lock)
|
||||
pthread_rwlock_wrlock(&machine->threads_lock);
|
||||
rb_erase_init(&th->rb_node, &machine->threads);
|
||||
|
|
|
@ -141,7 +141,7 @@ void map__init(struct map *map, enum map_type type,
|
|||
RB_CLEAR_NODE(&map->rb_node);
|
||||
map->groups = NULL;
|
||||
map->erange_warned = false;
|
||||
atomic_set(&map->refcnt, 1);
|
||||
refcount_set(&map->refcnt, 1);
|
||||
}
|
||||
|
||||
struct map *map__new(struct machine *machine, u64 start, u64 len,
|
||||
|
@ -255,7 +255,7 @@ void map__delete(struct map *map)
|
|||
|
||||
void map__put(struct map *map)
|
||||
{
|
||||
if (map && atomic_dec_and_test(&map->refcnt))
|
||||
if (map && refcount_dec_and_test(&map->refcnt))
|
||||
map__delete(map);
|
||||
}
|
||||
|
||||
|
@ -354,7 +354,7 @@ struct map *map__clone(struct map *from)
|
|||
struct map *map = memdup(from, sizeof(*map));
|
||||
|
||||
if (map != NULL) {
|
||||
atomic_set(&map->refcnt, 1);
|
||||
refcount_set(&map->refcnt, 1);
|
||||
RB_CLEAR_NODE(&map->rb_node);
|
||||
dso__get(map->dso);
|
||||
map->groups = NULL;
|
||||
|
@ -485,7 +485,7 @@ void map_groups__init(struct map_groups *mg, struct machine *machine)
|
|||
maps__init(&mg->maps[i]);
|
||||
}
|
||||
mg->machine = machine;
|
||||
atomic_set(&mg->refcnt, 1);
|
||||
refcount_set(&mg->refcnt, 1);
|
||||
}
|
||||
|
||||
static void __maps__purge(struct maps *maps)
|
||||
|
@ -547,7 +547,7 @@ void map_groups__delete(struct map_groups *mg)
|
|||
|
||||
void map_groups__put(struct map_groups *mg)
|
||||
{
|
||||
if (mg && atomic_dec_and_test(&mg->refcnt))
|
||||
if (mg && refcount_dec_and_test(&mg->refcnt))
|
||||
map_groups__delete(mg);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __PERF_MAP_H
|
||||
#define __PERF_MAP_H
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/refcount.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/rbtree.h>
|
||||
|
@ -51,7 +51,7 @@ struct map {
|
|||
|
||||
struct dso *dso;
|
||||
struct map_groups *groups;
|
||||
atomic_t refcnt;
|
||||
refcount_t refcnt;
|
||||
};
|
||||
|
||||
struct kmap {
|
||||
|
@ -67,7 +67,7 @@ struct maps {
|
|||
struct map_groups {
|
||||
struct maps maps[MAP__NR_TYPES];
|
||||
struct machine *machine;
|
||||
atomic_t refcnt;
|
||||
refcount_t refcnt;
|
||||
};
|
||||
|
||||
struct map_groups *map_groups__new(struct machine *machine);
|
||||
|
@ -77,7 +77,7 @@ bool map_groups__empty(struct map_groups *mg);
|
|||
static inline struct map_groups *map_groups__get(struct map_groups *mg)
|
||||
{
|
||||
if (mg)
|
||||
atomic_inc(&mg->refcnt);
|
||||
refcount_inc(&mg->refcnt);
|
||||
return mg;
|
||||
}
|
||||
|
||||
|
@ -150,7 +150,7 @@ struct map *map__clone(struct map *map);
|
|||
static inline struct map *map__get(struct map *map)
|
||||
{
|
||||
if (map)
|
||||
atomic_inc(&map->refcnt);
|
||||
refcount_inc(&map->refcnt);
|
||||
return map;
|
||||
}
|
||||
|
||||
|
|
|
@ -318,6 +318,7 @@ __add_event(struct list_head *list, int *idx,
|
|||
(*idx)++;
|
||||
evsel->cpus = cpu_map__get(cpus);
|
||||
evsel->own_cpus = cpu_map__get(cpus);
|
||||
evsel->system_wide = !!cpus;
|
||||
|
||||
if (name)
|
||||
evsel->name = strdup(name);
|
||||
|
|
|
@ -70,7 +70,7 @@ static void print_both_open_warning(int kerr, int uerr)
|
|||
}
|
||||
}
|
||||
|
||||
static int open_probe_events(const char *trace_file, bool readwrite)
|
||||
int open_trace_file(const char *trace_file, bool readwrite)
|
||||
{
|
||||
char buf[PATH_MAX];
|
||||
int ret;
|
||||
|
@ -92,12 +92,12 @@ static int open_probe_events(const char *trace_file, bool readwrite)
|
|||
|
||||
static int open_kprobe_events(bool readwrite)
|
||||
{
|
||||
return open_probe_events("kprobe_events", readwrite);
|
||||
return open_trace_file("kprobe_events", readwrite);
|
||||
}
|
||||
|
||||
static int open_uprobe_events(bool readwrite)
|
||||
{
|
||||
return open_probe_events("uprobe_events", readwrite);
|
||||
return open_trace_file("uprobe_events", readwrite);
|
||||
}
|
||||
|
||||
int probe_file__open(int flag)
|
||||
|
@ -899,6 +899,7 @@ bool probe_type_is_available(enum probe_type type)
|
|||
size_t len = 0;
|
||||
bool target_line = false;
|
||||
bool ret = probe_type_table[type].avail;
|
||||
int fd;
|
||||
|
||||
if (type >= PROBE_TYPE_END)
|
||||
return false;
|
||||
|
@ -906,14 +907,16 @@ bool probe_type_is_available(enum probe_type type)
|
|||
if (ret || probe_type_table[type].checked)
|
||||
return ret;
|
||||
|
||||
if (asprintf(&buf, "%s/README", tracing_path) < 0)
|
||||
fd = open_trace_file("README", false);
|
||||
if (fd < 0)
|
||||
return ret;
|
||||
|
||||
fp = fopen(buf, "r");
|
||||
if (!fp)
|
||||
goto end;
|
||||
fp = fdopen(fd, "r");
|
||||
if (!fp) {
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
zfree(&buf);
|
||||
while (getline(&buf, &len, fp) > 0 && !ret) {
|
||||
if (!target_line) {
|
||||
target_line = !!strstr(buf, " type: ");
|
||||
|
@ -928,7 +931,6 @@ bool probe_type_is_available(enum probe_type type)
|
|||
probe_type_table[type].avail = ret;
|
||||
|
||||
fclose(fp);
|
||||
end:
|
||||
free(buf);
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -35,6 +35,7 @@ enum probe_type {
|
|||
|
||||
/* probe-file.c depends on libelf */
|
||||
#ifdef HAVE_LIBELF_SUPPORT
|
||||
int open_trace_file(const char *trace_file, bool readwrite);
|
||||
int probe_file__open(int flag);
|
||||
int probe_file__open_both(int *kfd, int *ufd, int flag);
|
||||
struct strlist *probe_file__get_namelist(int fd);
|
||||
|
|
|
@ -1396,6 +1396,46 @@ struct sort_entry sort_transaction = {
|
|||
.se_width_idx = HISTC_TRANSACTION,
|
||||
};
|
||||
|
||||
/* --sort symbol_size */
|
||||
|
||||
static int64_t _sort__sym_size_cmp(struct symbol *sym_l, struct symbol *sym_r)
|
||||
{
|
||||
int64_t size_l = sym_l != NULL ? symbol__size(sym_l) : 0;
|
||||
int64_t size_r = sym_r != NULL ? symbol__size(sym_r) : 0;
|
||||
|
||||
return size_l < size_r ? -1 :
|
||||
size_l == size_r ? 0 : 1;
|
||||
}
|
||||
|
||||
static int64_t
|
||||
sort__sym_size_cmp(struct hist_entry *left, struct hist_entry *right)
|
||||
{
|
||||
return _sort__sym_size_cmp(right->ms.sym, left->ms.sym);
|
||||
}
|
||||
|
||||
static int _hist_entry__sym_size_snprintf(struct symbol *sym, char *bf,
|
||||
size_t bf_size, unsigned int width)
|
||||
{
|
||||
if (sym)
|
||||
return repsep_snprintf(bf, bf_size, "%*d", width, symbol__size(sym));
|
||||
|
||||
return repsep_snprintf(bf, bf_size, "%*s", width, "unknown");
|
||||
}
|
||||
|
||||
static int hist_entry__sym_size_snprintf(struct hist_entry *he, char *bf,
|
||||
size_t size, unsigned int width)
|
||||
{
|
||||
return _hist_entry__sym_size_snprintf(he->ms.sym, bf, size, width);
|
||||
}
|
||||
|
||||
struct sort_entry sort_sym_size = {
|
||||
.se_header = "Symbol size",
|
||||
.se_cmp = sort__sym_size_cmp,
|
||||
.se_snprintf = hist_entry__sym_size_snprintf,
|
||||
.se_width_idx = HISTC_SYM_SIZE,
|
||||
};
|
||||
|
||||
|
||||
struct sort_dimension {
|
||||
const char *name;
|
||||
struct sort_entry *entry;
|
||||
|
@ -1418,6 +1458,7 @@ static struct sort_dimension common_sort_dimensions[] = {
|
|||
DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
|
||||
DIM(SORT_TRANSACTION, "transaction", sort_transaction),
|
||||
DIM(SORT_TRACE, "trace", sort_trace),
|
||||
DIM(SORT_SYM_SIZE, "symbol_size", sort_sym_size),
|
||||
};
|
||||
|
||||
#undef DIM
|
||||
|
|
|
@ -211,6 +211,7 @@ enum sort_type {
|
|||
SORT_GLOBAL_WEIGHT,
|
||||
SORT_TRANSACTION,
|
||||
SORT_TRACE,
|
||||
SORT_SYM_SIZE,
|
||||
|
||||
/* branch stack specific sort keys */
|
||||
__SORT_BRANCH_STACK,
|
||||
|
|
|
@ -53,7 +53,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
|
|||
goto err_thread;
|
||||
|
||||
list_add(&comm->list, &thread->comm_list);
|
||||
atomic_set(&thread->refcnt, 1);
|
||||
refcount_set(&thread->refcnt, 1);
|
||||
RB_CLEAR_NODE(&thread->rb_node);
|
||||
}
|
||||
|
||||
|
@ -88,13 +88,13 @@ void thread__delete(struct thread *thread)
|
|||
struct thread *thread__get(struct thread *thread)
|
||||
{
|
||||
if (thread)
|
||||
atomic_inc(&thread->refcnt);
|
||||
refcount_inc(&thread->refcnt);
|
||||
return thread;
|
||||
}
|
||||
|
||||
void thread__put(struct thread *thread)
|
||||
{
|
||||
if (thread && atomic_dec_and_test(&thread->refcnt)) {
|
||||
if (thread && refcount_dec_and_test(&thread->refcnt)) {
|
||||
/*
|
||||
* Remove it from the dead_threads list, as last reference
|
||||
* is gone.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __PERF_THREAD_H
|
||||
#define __PERF_THREAD_H
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/refcount.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <linux/list.h>
|
||||
#include <unistd.h>
|
||||
|
@ -23,7 +23,7 @@ struct thread {
|
|||
pid_t tid;
|
||||
pid_t ppid;
|
||||
int cpu;
|
||||
atomic_t refcnt;
|
||||
refcount_t refcnt;
|
||||
char shortname[3];
|
||||
bool comm_set;
|
||||
int comm_len;
|
||||
|
|
|
@ -66,7 +66,7 @@ struct thread_map *thread_map__new_by_pid(pid_t pid)
|
|||
for (i = 0; i < items; i++)
|
||||
thread_map__set_pid(threads, i, atoi(namelist[i]->d_name));
|
||||
threads->nr = items;
|
||||
atomic_set(&threads->refcnt, 1);
|
||||
refcount_set(&threads->refcnt, 1);
|
||||
}
|
||||
|
||||
for (i=0; i<items; i++)
|
||||
|
@ -83,7 +83,7 @@ struct thread_map *thread_map__new_by_tid(pid_t tid)
|
|||
if (threads != NULL) {
|
||||
thread_map__set_pid(threads, 0, tid);
|
||||
threads->nr = 1;
|
||||
atomic_set(&threads->refcnt, 1);
|
||||
refcount_set(&threads->refcnt, 1);
|
||||
}
|
||||
|
||||
return threads;
|
||||
|
@ -105,7 +105,7 @@ struct thread_map *thread_map__new_by_uid(uid_t uid)
|
|||
goto out_free_threads;
|
||||
|
||||
threads->nr = 0;
|
||||
atomic_set(&threads->refcnt, 1);
|
||||
refcount_set(&threads->refcnt, 1);
|
||||
|
||||
while ((dirent = readdir(proc)) != NULL) {
|
||||
char *end;
|
||||
|
@ -235,7 +235,7 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str)
|
|||
out:
|
||||
strlist__delete(slist);
|
||||
if (threads)
|
||||
atomic_set(&threads->refcnt, 1);
|
||||
refcount_set(&threads->refcnt, 1);
|
||||
return threads;
|
||||
|
||||
out_free_namelist:
|
||||
|
@ -255,7 +255,7 @@ struct thread_map *thread_map__new_dummy(void)
|
|||
if (threads != NULL) {
|
||||
thread_map__set_pid(threads, 0, -1);
|
||||
threads->nr = 1;
|
||||
atomic_set(&threads->refcnt, 1);
|
||||
refcount_set(&threads->refcnt, 1);
|
||||
}
|
||||
return threads;
|
||||
}
|
||||
|
@ -300,7 +300,7 @@ struct thread_map *thread_map__new_by_tid_str(const char *tid_str)
|
|||
}
|
||||
out:
|
||||
if (threads)
|
||||
atomic_set(&threads->refcnt, 1);
|
||||
refcount_set(&threads->refcnt, 1);
|
||||
return threads;
|
||||
|
||||
out_free_threads:
|
||||
|
@ -326,7 +326,7 @@ static void thread_map__delete(struct thread_map *threads)
|
|||
if (threads) {
|
||||
int i;
|
||||
|
||||
WARN_ONCE(atomic_read(&threads->refcnt) != 0,
|
||||
WARN_ONCE(refcount_read(&threads->refcnt) != 0,
|
||||
"thread map refcnt unbalanced\n");
|
||||
for (i = 0; i < threads->nr; i++)
|
||||
free(thread_map__comm(threads, i));
|
||||
|
@ -337,13 +337,13 @@ static void thread_map__delete(struct thread_map *threads)
|
|||
struct thread_map *thread_map__get(struct thread_map *map)
|
||||
{
|
||||
if (map)
|
||||
atomic_inc(&map->refcnt);
|
||||
refcount_inc(&map->refcnt);
|
||||
return map;
|
||||
}
|
||||
|
||||
void thread_map__put(struct thread_map *map)
|
||||
{
|
||||
if (map && atomic_dec_and_test(&map->refcnt))
|
||||
if (map && refcount_dec_and_test(&map->refcnt))
|
||||
thread_map__delete(map);
|
||||
}
|
||||
|
||||
|
@ -423,7 +423,7 @@ static void thread_map__copy_event(struct thread_map *threads,
|
|||
threads->map[i].comm = strndup(event->entries[i].comm, 16);
|
||||
}
|
||||
|
||||
atomic_set(&threads->refcnt, 1);
|
||||
refcount_set(&threads->refcnt, 1);
|
||||
}
|
||||
|
||||
struct thread_map *thread_map__new_event(struct thread_map_event *event)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/refcount.h>
|
||||
|
||||
struct thread_map_data {
|
||||
pid_t pid;
|
||||
|
@ -11,7 +11,7 @@ struct thread_map_data {
|
|||
};
|
||||
|
||||
struct thread_map {
|
||||
atomic_t refcnt;
|
||||
refcount_t refcnt;
|
||||
int nr;
|
||||
struct thread_map_data map[];
|
||||
};
|
||||
|
|
|
@ -355,8 +355,8 @@ void print_binary(unsigned char *data, size_t len,
|
|||
size_t bytes_per_line, print_binary_t printer,
|
||||
void *extra);
|
||||
|
||||
#if !defined(__GLIBC__) && !defined(__ANDROID__)
|
||||
extern int sched_getcpu(void);
|
||||
#ifndef HAVE_SCHED_GETCPU_SUPPORT
|
||||
int sched_getcpu(void);
|
||||
#endif
|
||||
|
||||
int is_printable_array(char *p, unsigned int len);
|
||||
|
|
|
@ -43,6 +43,15 @@ ifneq ($(CC), clang)
|
|||
EXTRA_WARNINGS += -Wstrict-aliasing=3
|
||||
endif
|
||||
|
||||
# Hack to avoid type-punned warnings on old systems such as RHEL5:
|
||||
# We should be changing CFLAGS and checking gcc version, but this
|
||||
# will do for now and keep the above -Wstrict-aliasing=3 in place
|
||||
# in newer systems.
|
||||
# Needed for the __raw_cmpxchg in tools/arch/x86/include/asm/cmpxchg.h
|
||||
ifneq ($(filter 3.%,$(MAKE_VERSION)),) # make-3
|
||||
EXTRA_WARNINGS += -fno-strict-aliasing
|
||||
endif
|
||||
|
||||
ifneq ($(findstring $(MAKEFLAGS), w),w)
|
||||
PRINT_DIR = --no-print-directory
|
||||
else
|
||||
|
|
Загрузка…
Ссылка в новой задаче