Commit 84e5b549 authored by Ingo Molnar's avatar Ingo Molnar

Merge tag 'perf-core-for-mingo-4.11-20170306' of...

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: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents c1ae3cfa 001916b9
...@@ -12,7 +12,7 @@ kprobes can probe (this means, all functions body except for __kprobes ...@@ -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 functions). Unlike the Tracepoint based event, this can be added and removed
dynamically, on the fly. 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 Similar to the events tracer, this doesn't need to be activated via
current_tracer. Instead of that, add probe points via current_tracer. Instead of that, add probe points via
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
Overview Overview
-------- --------
Uprobe based trace events are similar to kprobe based trace events. 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 Similar to the kprobe-event tracer, this doesn't need to be activated via
current_tracer. Instead of that, add probe points via current_tracer. Instead of that, add probe points via
......
...@@ -609,7 +609,7 @@ CONFIG_SCHED_TRACER=y ...@@ -609,7 +609,7 @@ CONFIG_SCHED_TRACER=y
CONFIG_FTRACE_SYSCALLS=y CONFIG_FTRACE_SYSCALLS=y
CONFIG_STACK_TRACER=y CONFIG_STACK_TRACER=y
CONFIG_BLK_DEV_IO_TRACE=y CONFIG_BLK_DEV_IO_TRACE=y
CONFIG_UPROBE_EVENT=y CONFIG_UPROBE_EVENTS=y
CONFIG_FUNCTION_PROFILER=y CONFIG_FUNCTION_PROFILER=y
CONFIG_HIST_TRIGGERS=y CONFIG_HIST_TRIGGERS=y
CONFIG_TRACE_ENUM_MAP_FILE=y CONFIG_TRACE_ENUM_MAP_FILE=y
......
...@@ -560,7 +560,7 @@ CONFIG_SCHED_TRACER=y ...@@ -560,7 +560,7 @@ CONFIG_SCHED_TRACER=y
CONFIG_FTRACE_SYSCALLS=y CONFIG_FTRACE_SYSCALLS=y
CONFIG_STACK_TRACER=y CONFIG_STACK_TRACER=y
CONFIG_BLK_DEV_IO_TRACE=y CONFIG_BLK_DEV_IO_TRACE=y
CONFIG_UPROBE_EVENT=y CONFIG_UPROBE_EVENTS=y
CONFIG_FUNCTION_PROFILER=y CONFIG_FUNCTION_PROFILER=y
CONFIG_HIST_TRIGGERS=y CONFIG_HIST_TRIGGERS=y
CONFIG_TRACE_ENUM_MAP_FILE=y CONFIG_TRACE_ENUM_MAP_FILE=y
......
...@@ -558,7 +558,7 @@ CONFIG_SCHED_TRACER=y ...@@ -558,7 +558,7 @@ CONFIG_SCHED_TRACER=y
CONFIG_FTRACE_SYSCALLS=y CONFIG_FTRACE_SYSCALLS=y
CONFIG_STACK_TRACER=y CONFIG_STACK_TRACER=y
CONFIG_BLK_DEV_IO_TRACE=y CONFIG_BLK_DEV_IO_TRACE=y
CONFIG_UPROBE_EVENT=y CONFIG_UPROBE_EVENTS=y
CONFIG_FUNCTION_PROFILER=y CONFIG_FUNCTION_PROFILER=y
CONFIG_HIST_TRIGGERS=y CONFIG_HIST_TRIGGERS=y
CONFIG_TRACE_ENUM_MAP_FILE=y CONFIG_TRACE_ENUM_MAP_FILE=y
......
...@@ -179,7 +179,7 @@ CONFIG_FTRACE_SYSCALLS=y ...@@ -179,7 +179,7 @@ CONFIG_FTRACE_SYSCALLS=y
CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP=y CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP=y
CONFIG_STACK_TRACER=y CONFIG_STACK_TRACER=y
CONFIG_BLK_DEV_IO_TRACE=y CONFIG_BLK_DEV_IO_TRACE=y
CONFIG_UPROBE_EVENT=y CONFIG_UPROBE_EVENTS=y
CONFIG_FUNCTION_PROFILER=y CONFIG_FUNCTION_PROFILER=y
CONFIG_TRACE_ENUM_MAP_FILE=y CONFIG_TRACE_ENUM_MAP_FILE=y
CONFIG_KPROBES_SANITY_TEST=y CONFIG_KPROBES_SANITY_TEST=y
......
...@@ -67,7 +67,7 @@ ...@@ -67,7 +67,7 @@
#endif #endif
/* Ensure if the instruction can be boostable */ /* 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 */ /* Recover instruction if given address is probed */
extern unsigned long recover_probed_instruction(kprobe_opcode_t *buf, extern unsigned long recover_probed_instruction(kprobe_opcode_t *buf,
unsigned long addr); unsigned long addr);
......
...@@ -167,12 +167,12 @@ NOKPROBE_SYMBOL(skip_prefixes); ...@@ -167,12 +167,12 @@ NOKPROBE_SYMBOL(skip_prefixes);
* Returns non-zero if opcode is boostable. * Returns non-zero if opcode is boostable.
* RIP relative instructions are adjusted at copying time in 64 bits mode * 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 opcode;
kprobe_opcode_t *orig_opcodes = opcodes; 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. */ return 0; /* Page fault may occur on this address. */
retry: retry:
...@@ -417,7 +417,7 @@ static int arch_copy_kprobe(struct kprobe *p) ...@@ -417,7 +417,7 @@ static int arch_copy_kprobe(struct kprobe *p)
* __copy_instruction can modify the displacement of the instruction, * __copy_instruction can modify the displacement of the instruction,
* but it doesn't affect boostable check. * 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; p->ainsn.boostable = 0;
else else
p->ainsn.boostable = -1; p->ainsn.boostable = -1;
......
...@@ -178,7 +178,7 @@ static int copy_optimized_instructions(u8 *dest, u8 *src) ...@@ -178,7 +178,7 @@ static int copy_optimized_instructions(u8 *dest, u8 *src)
while (len < RELATIVEJUMP_SIZE) { while (len < RELATIVEJUMP_SIZE) {
ret = __copy_instruction(dest + len, src + len); ret = __copy_instruction(dest + len, src + len);
if (!ret || !can_boost(dest + len)) if (!ret || !can_boost(dest + len, src + len))
return -EINVAL; return -EINVAL;
len += ret; len += ret;
} }
......
...@@ -267,6 +267,7 @@ extern int arch_init_kprobes(void); ...@@ -267,6 +267,7 @@ extern int arch_init_kprobes(void);
extern void show_registers(struct pt_regs *regs); extern void show_registers(struct pt_regs *regs);
extern void kprobes_inc_nmissed_count(struct kprobe *p); extern void kprobes_inc_nmissed_count(struct kprobe *p);
extern bool arch_within_kprobe_blacklist(unsigned long addr); 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); extern bool within_kprobe_blacklist(unsigned long addr);
......
...@@ -1875,12 +1875,25 @@ static int pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs) ...@@ -1875,12 +1875,25 @@ static int pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs)
} }
NOKPROBE_SYMBOL(pre_handler_kretprobe); NOKPROBE_SYMBOL(pre_handler_kretprobe);
bool __weak arch_function_offset_within_entry(unsigned long offset)
{
return !offset;
}
int register_kretprobe(struct kretprobe *rp) int register_kretprobe(struct kretprobe *rp)
{ {
int ret = 0; int ret = 0;
struct kretprobe_instance *inst; struct kretprobe_instance *inst;
int i; int i;
void *addr; 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) { if (kretprobe_blacklist_size) {
addr = kprobe_addr(&rp->kp); addr = kprobe_addr(&rp->kp);
......
...@@ -429,7 +429,7 @@ config BLK_DEV_IO_TRACE ...@@ -429,7 +429,7 @@ config BLK_DEV_IO_TRACE
If unsure, say N. If unsure, say N.
config KPROBE_EVENT config KPROBE_EVENTS
depends on KPROBES depends on KPROBES
depends on HAVE_REGS_AND_STACK_ACCESS_API depends on HAVE_REGS_AND_STACK_ACCESS_API
bool "Enable kprobes-based dynamic events" bool "Enable kprobes-based dynamic events"
...@@ -447,7 +447,7 @@ config KPROBE_EVENT ...@@ -447,7 +447,7 @@ config KPROBE_EVENT
This option is also required by perf-probe subcommand of perf tools. This option is also required by perf-probe subcommand of perf tools.
If you want to use perf tools, this option is strongly recommended. If you want to use perf tools, this option is strongly recommended.
config UPROBE_EVENT config UPROBE_EVENTS
bool "Enable uprobes-based dynamic events" bool "Enable uprobes-based dynamic events"
depends on ARCH_SUPPORTS_UPROBES depends on ARCH_SUPPORTS_UPROBES
depends on MMU depends on MMU
...@@ -466,7 +466,7 @@ config UPROBE_EVENT ...@@ -466,7 +466,7 @@ config UPROBE_EVENT
config BPF_EVENTS config BPF_EVENTS
depends on BPF_SYSCALL depends on BPF_SYSCALL
depends on (KPROBE_EVENT || UPROBE_EVENT) && PERF_EVENTS depends on (KPROBE_EVENTS || UPROBE_EVENTS) && PERF_EVENTS
bool bool
default y default y
help help
......
...@@ -57,7 +57,7 @@ obj-$(CONFIG_EVENT_TRACING) += trace_events_filter.o ...@@ -57,7 +57,7 @@ obj-$(CONFIG_EVENT_TRACING) += trace_events_filter.o
obj-$(CONFIG_EVENT_TRACING) += trace_events_trigger.o obj-$(CONFIG_EVENT_TRACING) += trace_events_trigger.o
obj-$(CONFIG_HIST_TRIGGERS) += trace_events_hist.o obj-$(CONFIG_HIST_TRIGGERS) += trace_events_hist.o
obj-$(CONFIG_BPF_EVENTS) += bpf_trace.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 obj-$(CONFIG_TRACEPOINTS) += power-traces.o
ifeq ($(CONFIG_PM),y) ifeq ($(CONFIG_PM),y)
obj-$(CONFIG_TRACEPOINTS) += rpm-traces.o obj-$(CONFIG_TRACEPOINTS) += rpm-traces.o
...@@ -66,7 +66,7 @@ ifeq ($(CONFIG_TRACING),y) ...@@ -66,7 +66,7 @@ ifeq ($(CONFIG_TRACING),y)
obj-$(CONFIG_KGDB_KDB) += trace_kdb.o obj-$(CONFIG_KGDB_KDB) += trace_kdb.o
endif endif
obj-$(CONFIG_PROBE_EVENTS) += trace_probe.o 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 obj-$(CONFIG_TRACEPOINT_BENCHMARK) += trace_benchmark.o
......
...@@ -4341,22 +4341,23 @@ static const char readme_msg[] = ...@@ -4341,22 +4341,23 @@ static const char readme_msg[] =
"\t\t\t traces\n" "\t\t\t traces\n"
#endif #endif
#endif /* CONFIG_STACK_TRACER */ #endif /* CONFIG_STACK_TRACER */
#ifdef CONFIG_KPROBE_EVENT #ifdef CONFIG_KPROBE_EVENTS
" kprobe_events\t\t- Add/remove/show the kernel dynamic events\n" " 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" "\t\t\t Write into this file to define/undefine new trace events.\n"
#endif #endif
#ifdef CONFIG_UPROBE_EVENT #ifdef CONFIG_UPROBE_EVENTS
" uprobe_events\t\t- Add/remove/show the userspace dynamic events\n" " 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" "\t\t\t Write into this file to define/undefine new trace events.\n"
#endif #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 accepts: event-definitions (one definition per line)\n"
"\t Format: p|r[:[<group>/]<event>] <place> [<args>]\n" "\t Format: p|r[:[<group>/]<event>] <place> [<args>]\n"
"\t -:[<group>/]<event>\n" "\t -:[<group>/]<event>\n"
#ifdef CONFIG_KPROBE_EVENT #ifdef CONFIG_KPROBE_EVENTS
"\t place: [<module>:]<symbol>[+<offset>]|<memaddr>\n" "\t place: [<module>:]<symbol>[+<offset>]|<memaddr>\n"
"place (kretprobe): [<module>:]<symbol>[+<offset>]|<memaddr>\n"
#endif #endif
#ifdef CONFIG_UPROBE_EVENT #ifdef CONFIG_UPROBE_EVENTS
"\t place: <path>:<offset>\n" "\t place: <path>:<offset>\n"
#endif #endif
"\t args: <name>=fetcharg[:type]\n" "\t args: <name>=fetcharg[:type]\n"
......
...@@ -681,10 +681,6 @@ static int create_trace_kprobe(int argc, char **argv) ...@@ -681,10 +681,6 @@ static int create_trace_kprobe(int argc, char **argv)
return -EINVAL; return -EINVAL;
} }
if (isdigit(argv[1][0])) { if (isdigit(argv[1][0])) {
if (is_return) {
pr_info("Return probe point must be a symbol.\n");
return -EINVAL;
}
/* an address specified */ /* an address specified */
ret = kstrtoul(&argv[1][0], 0, (unsigned long *)&addr); ret = kstrtoul(&argv[1][0], 0, (unsigned long *)&addr);
if (ret) { if (ret) {
...@@ -700,8 +696,9 @@ static int create_trace_kprobe(int argc, char **argv) ...@@ -700,8 +696,9 @@ static int create_trace_kprobe(int argc, char **argv)
pr_info("Failed to parse symbol.\n"); pr_info("Failed to parse symbol.\n");
return ret; return ret;
} }
if (offset && is_return) { if (offset && is_return &&
pr_info("Return probe must be used without offset.\n"); !arch_function_offset_within_entry(offset)) {
pr_info("Given offset is not valid for return probe.\n");
return -EINVAL; return -EINVAL;
} }
} }
......
...@@ -248,7 +248,7 @@ ASSIGN_FETCH_FUNC(file_offset, ftype), \ ...@@ -248,7 +248,7 @@ ASSIGN_FETCH_FUNC(file_offset, ftype), \
#define FETCH_TYPE_STRING 0 #define FETCH_TYPE_STRING 0
#define FETCH_TYPE_STRSIZE 1 #define FETCH_TYPE_STRSIZE 1
#ifdef CONFIG_KPROBE_EVENT #ifdef CONFIG_KPROBE_EVENTS
struct symbol_cache; struct symbol_cache;
unsigned long update_symbol_cache(struct symbol_cache *sc); unsigned long update_symbol_cache(struct symbol_cache *sc);
void free_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) ...@@ -278,7 +278,7 @@ alloc_symbol_cache(const char *sym, long offset)
{ {
return NULL; return NULL;
} }
#endif /* CONFIG_KPROBE_EVENT */ #endif /* CONFIG_KPROBE_EVENTS */
struct probe_arg { struct probe_arg {
struct fetch_param fetch; struct fetch_param fetch;
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
#define LOCK_PREFIX "\n\tlock; " #define LOCK_PREFIX "\n\tlock; "
#include <asm/cmpxchg.h>
/* /*
* Atomic operations that C can't guarantee us. Useful for * Atomic operations that C can't guarantee us. Useful for
* resource counting etc.. * resource counting etc..
...@@ -62,4 +64,9 @@ static inline int atomic_dec_and_test(atomic_t *v) ...@@ -62,4 +64,9 @@ static inline int atomic_dec_and_test(atomic_t *v)
GEN_UNARY_RMWcc(LOCK_PREFIX "decl", v->counter, "%0", "e"); 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 */ #endif /* _TOOLS_LINUX_ASM_X86_ATOMIC_H */
#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 := \ ...@@ -63,6 +63,7 @@ FEATURE_TESTS_BASIC := \
lzma \ lzma \
get_cpuid \ get_cpuid \
bpf \ bpf \
sched_getcpu \
sdt sdt
# FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list # FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list
......
...@@ -48,12 +48,13 @@ FILES= \ ...@@ -48,12 +48,13 @@ FILES= \
test-get_cpuid.bin \ test-get_cpuid.bin \
test-sdt.bin \ test-sdt.bin \
test-cxx.bin \ test-cxx.bin \
test-jvmti.bin test-jvmti.bin \
test-sched_getcpu.bin
FILES := $(addprefix $(OUTPUT),$(FILES)) FILES := $(addprefix $(OUTPUT),$(FILES))
CC := $(CROSS_COMPILE)gcc -MD CC ?= $(CROSS_COMPILE)gcc -MD
CXX := $(CROSS_COMPILE)g++ -MD CXX ?= $(CROSS_COMPILE)g++ -MD
PKG_CONFIG := $(CROSS_COMPILE)pkg-config PKG_CONFIG := $(CROSS_COMPILE)pkg-config
LLVM_CONFIG ?= llvm-config LLVM_CONFIG ?= llvm-config
...@@ -91,6 +92,9 @@ $(OUTPUT)test-libelf.bin: ...@@ -91,6 +92,9 @@ $(OUTPUT)test-libelf.bin:
$(OUTPUT)test-glibc.bin: $(OUTPUT)test-glibc.bin:
$(BUILD) $(BUILD)
$(OUTPUT)test-sched_getcpu.bin:
$(BUILD)
DWARFLIBS := -ldw DWARFLIBS := -ldw
ifeq ($(findstring -static,${LDFLAGS}),-static) ifeq ($(findstring -static,${LDFLAGS}),-static)
DWARFLIBS += -lelf -lebl -lz -llzma -lbz2 DWARFLIBS += -lelf -lebl -lz -llzma -lbz2
......
...@@ -117,6 +117,10 @@ ...@@ -117,6 +117,10 @@
# include "test-pthread-attr-setaffinity-np.c" # include "test-pthread-attr-setaffinity-np.c"
#undef main #undef main
#define main main_test_sched_getcpu
# include "test-sched_getcpu.c"
#undef main
# if 0 # if 0
/* /*
* Disable libbabeltrace check for test-all, because the requested * Disable libbabeltrace check for test-all, because the requested
...@@ -182,6 +186,7 @@ int main(int argc, char *argv[]) ...@@ -182,6 +186,7 @@ int main(int argc, char *argv[])
main_test_get_cpuid(); main_test_get_cpuid();
main_test_bpf(); main_test_bpf();
main_test_libcrypto(); main_test_libcrypto();
main_test_sched_getcpu();
main_test_sdt(); main_test_sdt();
return 0; return 0;
......
#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) ...@@ -60,4 +60,12 @@ static inline int atomic_dec_and_test(atomic_t *v)
return __sync_sub_and_fetch(&v->counter, 1) == 0; 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 */ #endif /* __TOOLS_ASM_GENERIC_ATOMIC_H */
...@@ -3,4 +3,10 @@ ...@@ -3,4 +3,10 @@
#include <asm/atomic.h> #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 */ #endif /* __TOOLS_LINUX_ATOMIC_H */
...@@ -12,3 +12,7 @@ ...@@ -12,3 +12,7 @@
#if GCC_VERSION >= 70000 && !defined(__CHECKER__) #if GCC_VERSION >= 70000 && !defined(__CHECKER__)
# define __fallthrough __attribute__ ((fallthrough)) # define __fallthrough __attribute__ ((fallthrough))
#endif #endif
#if GCC_VERSION >= 40300
# define __compiletime_error(message) __attribute__((error(message)))
#endif /* GCC_VERSION >= 40300 */
...@@ -5,6 +5,10 @@ ...@@ -5,6 +5,10 @@
#include <linux/compiler-gcc.h> #include <linux/compiler-gcc.h>
#endif #endif
#ifndef __compiletime_error
# define __compiletime_error(message)
#endif
/* Optimization barrier */ /* Optimization barrier */
/* The "volatile" is due to gcc bugs */ /* The "volatile" is due to gcc bugs */
#define barrier() __asm__ __volatile__("": : :"memory") #define barrier() __asm__ __volatile__("": : :"memory")
......
...@@ -5,6 +5,10 @@ ...@@ -5,6 +5,10 @@
#include <stddef.h> #include <stddef.h>
#include <assert.h> #include <assert.h>
#ifndef UINT_MAX
#define UINT_MAX (~0U)
#endif
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
#define PERF_ALIGN(x, a) __PERF_ALIGN_MASK(x, (typeof(x))(a)-1) #define PERF_ALIGN(x, a) __PERF_ALIGN_MASK(x, (typeof(x))(a)-1)
......
#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 ...@@ -30,6 +30,24 @@ OPTIONS
--verbose=:: --verbose=::
Verbosity level. 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 SEE ALSO
-------- --------
......
...@@ -80,6 +80,7 @@ OPTIONS ...@@ -80,6 +80,7 @@ OPTIONS
- pid: command and tid of the task - pid: command and tid of the task
- dso: name of library or module executed at the time of sample - dso: name of library or module executed at the time of sample
- symbol: name of function 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 - parent: name of function matched to the parent regex filter. Unmatched
entries are displayed as "[other]". entries are displayed as "[other]".
- cpu: cpu number the task ran at the time of sample - cpu: cpu number the task ran at the time of sample
......
...@@ -12,6 +12,7 @@ tools/arch/sparc/include/asm/barrier_32.h ...@@ -12,6 +12,7 @@ tools/arch/sparc/include/asm/barrier_32.h
tools/arch/sparc/include/asm/barrier_64.h tools/arch/sparc/include/asm/barrier_64.h
tools/arch/tile/include/asm/barrier.h tools/arch/tile/include/asm/barrier.h
tools/arch/x86/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/cpufeatures.h
tools/arch/x86/include/asm/disabled-features.h tools/arch/x86/include/asm/disabled-features.h
tools/arch/x86/include/asm/required-features.h tools/arch/x86/include/asm/required-features.h
...@@ -78,6 +79,7 @@ tools/include/uapi/linux/perf_event.h ...@@ -78,6 +79,7 @@ tools/include/uapi/linux/perf_event.h
tools/include/linux/poison.h tools/include/linux/poison.h
tools/include/linux/rbtree.h tools/include/linux/rbtree.h
tools/include/linux/rbtree_augmented.h tools/include/linux/rbtree_augmented.h
tools/include/linux/refcount.h
tools/include/linux/string.h tools/include/linux/string.h
tools/include/linux/stringify.h tools/include/linux/stringify.h
tools/include/linux/types.h tools/include/linux/types.h
......
...@@ -317,6 +317,10 @@ ifdef NO_DWARF ...@@ -317,6 +317,10 @@ ifdef NO_DWARF
NO_LIBDW_DWARF_UNWIND := 1 NO_LIBDW_DWARF_UNWIND := 1
endif endif
ifeq ($(feature-sched_getcpu), 1)
CFLAGS += -DHAVE_SCHED_GETCPU_SUPPORT
endif
ifndef NO_LIBELF ifndef NO_LIBELF
CFLAGS += -DHAVE_LIBELF_SUPPORT CFLAGS += -DHAVE_LIBELF_SUPPORT
EXTLIBS += -lelf EXTLIBS += -lelf
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
*/ */
/* For the CLR_() macros */ /* For the CLR_() macros */
#include <string.h>
#include <pthread.h> #include <pthread.h>
#include <errno.h> #include <errno.h>
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
*/ */
/* For the CLR_() macros */ /* For the CLR_() macros */
#include <string.h>
#include <pthread.h> #include <pthread.h>
#include <signal.h> #include <signal.h>
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
*/ */
/* For the CLR_() macros */ /* For the CLR_() macros */
#include <string.h>
#include <pthread.h> #include <pthread.h>
#include <signal.h> #include <signal.h>
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
*/ */
/* For the CLR_() macros */ /* For the CLR_() macros */
#include <string.h>
#include <pthread.h> #include <pthread.h>
#include <signal.h> #include <signal.h>
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
*/ */
/* For the CLR_() macros */ /* For the CLR_() macros */
#include <string.h>
#include <pthread.h> #include <pthread.h>
#include <signal.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 ...@@ -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 #ifndef HAVE_PTHREAD_ATTR_SETAFFINITY_NP
#include <pthread.h> #include <pthread.h>
static inline int pthread_attr_setaffinity_np(pthread_attr_t *attr, #include <linux/compiler.h>
size_t cpusetsize, static inline int pthread_attr_setaffinity_np(pthread_attr_t *attr __maybe_unused,
cpu_set_t *cpuset) size_t cpusetsize __maybe_unused,
cpu_set_t *cpuset __maybe_unused)
{ {
attr = attr;
cpusetsize = cpusetsize;
cpuset = cpuset;
return 0; return 0;
} }
#endif #endif
......
...@@ -187,7 +187,8 @@ static const struct option options[] = { ...@@ -187,7 +187,8 @@ static const struct option options[] = {
OPT_INCR ('d', "show_details" , &p0.show_details, "Show details"), OPT_INCR ('d', "show_details" , &p0.show_details, "Show details"),
OPT_INCR ('a', "all" , &p0.run_all, "Run all tests in the suite"), 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_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('m', "measure_convergence", &p0.measure_convergence, "measure convergence latency"),
OPT_BOOLEAN('q', "quiet" , &p0.show_quiet, "quiet mode"), OPT_BOOLEAN('q', "quiet" , &p0.show_quiet, "quiet mode"),
OPT_BOOLEAN('S', "serialize-startup", &p0.serialize_startup,"serialize thread startup"), OPT_BOOLEAN('S', "serialize-startup", &p0.serialize_startup,"serialize thread startup"),
......
...@@ -11,11 +11,13 @@ ...@@ -11,11 +11,13 @@
#include <unistd.h> #include <unistd.h>
#include <signal.h> #include <signal.h>
#include <fcntl.h>
#include "debug.h" #include "debug.h"
#include <subcmd/parse-options.h> #include <subcmd/parse-options.h>
#include "evlist.h" #include "evlist.h"
#include "target.h" #include "target.h"
#include "cpumap.h"
#include "thread_map.h" #include "thread_map.h"
#include "util/config.h" #include "util/config.h"
...@@ -50,11 +52,12 @@ static void ftrace__workload_exec_failed_signal(int signo __maybe_unused, ...@@ -50,11 +52,12 @@ static void ftrace__workload_exec_failed_signal(int signo __maybe_unused,
done = true; 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; char *file;
int fd, ret = -1; int fd, ret = -1;
ssize_t size = strlen(val); ssize_t size = strlen(val);
int flags = O_WRONLY;
file = get_tracing_file(name); file = get_tracing_file(name);
if (!file) { if (!file) {
...@@ -62,7 +65,12 @@ static int write_tracing_file(const char *name, const char *val) ...@@ -62,7 +65,12 @@ static int write_tracing_file(const char *name, const char *val)
return -1; return -1;
} }
fd = open(file, O_WRONLY); if (append)
flags |= O_APPEND;
else
flags |= O_TRUNC;
fd = open(file, flags);
if (fd < 0) { if (fd < 0) {
pr_debug("cannot open tracing file: %s\n", name); pr_debug("cannot open tracing file: %s\n", name);
goto out; goto out;
...@@ -79,6 +87,18 @@ static int write_tracing_file(const char *name, const char *val) ...@@ -79,6 +87,18 @@ static int write_tracing_file(const char *name, const char *val)
return ret; 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) static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused)
{ {
if (write_tracing_file("tracing_on", "0") < 0) if (write_tracing_file("tracing_on", "0") < 0)
...@@ -90,14 +110,78 @@ static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused) ...@@ -90,14 +110,78 @@ static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused)
if (write_tracing_file("set_ftrace_pid", " ") < 0) if (write_tracing_file("set_ftrace_pid", " ") < 0)
return -1; 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; 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) static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
{ {
char *trace_file; char *trace_file;
int trace_fd; int trace_fd;
char *trace_pid;
char buf[4096]; char buf[4096];
struct pollfd pollfd = { struct pollfd pollfd = {
.events = POLLIN, .events = POLLIN,
...@@ -108,42 +192,43 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv) ...@@ -108,42 +192,43 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
return -1; return -1;
} }
if (argc < 1)
return -1;
signal(SIGINT, sig_handler); signal(SIGINT, sig_handler);
signal(SIGUSR1, sig_handler); signal(SIGUSR1, sig_handler);
signal(SIGCHLD, 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 */ /* reset ftrace buffer */
if (write_tracing_file("trace", "0") < 0) if (write_tracing_file("trace", "0") < 0)
goto out; goto out;
if (perf_evlist__prepare_workload(ftrace->evlist, &ftrace->target, if (argc && perf_evlist__prepare_workload(ftrace->evlist,
argv, false, ftrace__workload_exec_failed_signal) < 0) &ftrace->target, argv, false,
ftrace__workload_exec_failed_signal) < 0) {
goto out; goto out;
}
if (write_tracing_file("current_tracer", ftrace->tracer) < 0) { if (set_tracing_pid(ftrace) < 0) {
pr_err("failed to set current_tracer to %s\n", ftrace->tracer); pr_err("failed to set ftrace pid\n");
goto out; goto out_reset;
} }
if (asprintf(&trace_pid, "%d", thread_map__pid(ftrace->evlist->threads, 0)) < 0) { if (set_tracing_cpu(ftrace) < 0) {
pr_err("failed to allocate pid string\n"); pr_err("failed to set tracing cpumask\n");
goto out; goto out_reset;
} }
if (write_tracing_file("set_ftrace_pid", trace_pid) < 0) { if (write_tracing_file("current_tracer", ftrace->tracer) < 0) {
pr_err("failed to set pid: %s\n", trace_pid); pr_err("failed to set current_tracer to %s\n", ftrace->tracer);
goto out_free_pid; goto out_reset;
} }
trace_file = get_tracing_file("trace_pipe"); trace_file = get_tracing_file("trace_pipe");
if (!trace_file) { if (!trace_file) {
pr_err("failed to open trace_pipe\n"); pr_err("failed to open trace_pipe\n");
goto out_free_pid; goto out_reset;
} }
trace_fd = open(trace_file, O_RDONLY); trace_fd = open(trace_file, O_RDONLY);
...@@ -152,7 +237,7 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv) ...@@ -152,7 +237,7 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
if (trace_fd < 0) { if (trace_fd < 0) {
pr_err("failed to open trace_pipe\n"); pr_err("failed to open trace_pipe\n");
goto out_free_pid; goto out_reset;
} }
fcntl(trace_fd, F_SETFL, O_NONBLOCK); fcntl(trace_fd, F_SETFL, O_NONBLOCK);
...@@ -163,6 +248,8 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv) ...@@ -163,6 +248,8 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
goto out_close_fd; goto out_close_fd;
} }
setup_pager();
perf_evlist__start_workload(ftrace->evlist); perf_evlist__start_workload(ftrace->evlist);
while (!done) { while (!done) {
...@@ -191,11 +278,9 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv) ...@@ -191,11 +278,9 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
out_close_fd: out_close_fd:
close(trace_fd); close(trace_fd);
out_free_pid: out_reset:
free(trace_pid);
out:
reset_tracing_files(ftrace); reset_tracing_files(ftrace);
out:
return done ? 0 : -1; return done ? 0 : -1;
} }
...@@ -227,15 +312,21 @@ int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -227,15 +312,21 @@ int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused)
.target = { .uid = UINT_MAX, }, .target = { .uid = UINT_MAX, },
}; };
const char * const ftrace_usage[] = { const char * const ftrace_usage[] = {
"perf ftrace [<options>] <command>", "perf ftrace [<options>] [<command>]",
"perf ftrace [<options>] -- <command> [<options>]", "perf ftrace [<options>] -- <command> [<options>]",
NULL NULL
}; };
const struct option ftrace_options[] = { const struct option ftrace_options[] = {
OPT_STRING('t', "tracer", &ftrace.tracer, "tracer", OPT_STRING('t', "tracer", &ftrace.tracer, "tracer",
"tracer to use: function_graph(default) or function"), "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, OPT_INCR('v', "verbose", &verbose,
"be more 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() OPT_END()
}; };
...@@ -245,9 +336,18 @@ int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -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, argc = parse_options(argc, argv, ftrace_options, ftrace_usage,
PARSE_OPT_STOP_AT_NON_OPTION); PARSE_OPT_STOP_AT_NON_OPTION);
if (!argc) if (!argc && target__none(&ftrace.target))
usage_with_options(ftrace_usage, ftrace_options); 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(); ftrace.evlist = perf_evlist__new();
if (ftrace.evlist == NULL) if (ftrace.evlist == NULL)
return -ENOMEM; return -ENOMEM;
......
...@@ -146,6 +146,7 @@ static aggr_get_id_t aggr_get_id; ...@@ -146,6 +146,7 @@ static aggr_get_id_t aggr_get_id;
static bool append_file; static bool append_file;
static const char *output_name; static const char *output_name;
static int output_fd; static int output_fd;
static int print_free_counters_hint;
struct perf_stat { struct perf_stat {
bool record; bool record;
...@@ -1109,6 +1110,9 @@ static void printout(int id, int nr, struct perf_evsel *counter, double uval, ...@@ -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, counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
csv_sep); csv_sep);
if (counter->supported)
print_free_counters_hint = 1;
fprintf(stat_config.output, "%-*s%s", fprintf(stat_config.output, "%-*s%s",
csv_output ? 0 : unit_width, csv_output ? 0 : unit_width,
counter->unit, csv_sep); counter->unit, csv_sep);
...@@ -1477,6 +1481,13 @@ static void print_footer(void) ...@@ -1477,6 +1481,13 @@ static void print_footer(void)
avg_stats(&walltime_nsecs_stats)); avg_stats(&walltime_nsecs_stats));
} }
fprintf(output, "\n\n"); 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) 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) ...@@ -2339,6 +2350,35 @@ static int __cmd_report(int argc, const char **argv)
return 0; 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) int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
{ {
const char * const stat_usage[] = { const char * const stat_usage[] = {
...@@ -2445,9 +2485,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -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 */ } else if (big_num_opt == 0) /* User passed --no-big-num */
big_num = false; big_num = false;
/* Make system wide (-a) the default target. */ setup_system_wide(argc);
if (!argc && target__none(&target))
target.system_wide = true;
if (run_count < 0) { if (run_count < 0) {
pr_err("Run count must be a positive number\n"); pr_err("Run count must be a positive number\n");
......
...@@ -17,6 +17,7 @@ GenuineIntel-6-3A,v18,ivybridge,core ...@@ -17,6 +17,7 @@ GenuineIntel-6-3A,v18,ivybridge,core
GenuineIntel-6-3E,v19,ivytown,core GenuineIntel-6-3E,v19,ivytown,core
GenuineIntel-6-2D,v20,jaketown,core GenuineIntel-6-2D,v20,jaketown,core
GenuineIntel-6-57,v9,knightslanding,core GenuineIntel-6-57,v9,knightslanding,core
GenuineIntel-6-85,v9,knightslanding,core
GenuineIntel-6-1E,v2,nehalemep,core GenuineIntel-6-1E,v2,nehalemep,core
GenuineIntel-6-1F,v2,nehalemep,core GenuineIntel-6-1F,v2,nehalemep,core
GenuineIntel-6-1A,v2,nehalemep,core GenuineIntel-6-1A,v2,nehalemep,core
......
...@@ -66,7 +66,7 @@ static int process_event_cpus(struct perf_tool *tool __maybe_unused, ...@@ -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 nr", map->nr == 2);
TEST_ASSERT_VAL("wrong cpu", map->map[0] == 1); TEST_ASSERT_VAL("wrong cpu", map->map[0] == 1);
TEST_ASSERT_VAL("wrong cpu", map->map[1] == 256); 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); cpu_map__put(map);
return 0; return 0;
} }
......
...@@ -29,7 +29,7 @@ int test__thread_map(int subtest __maybe_unused) ...@@ -29,7 +29,7 @@ int test__thread_map(int subtest __maybe_unused)
thread_map__comm(map, 0) && thread_map__comm(map, 0) &&
!strcmp(thread_map__comm(map, 0), NAME)); !strcmp(thread_map__comm(map, 0), NAME));
TEST_ASSERT_VAL("wrong refcnt", TEST_ASSERT_VAL("wrong refcnt",
atomic_read(&map->refcnt) == 1); refcount_read(&map->refcnt) == 1);
thread_map__put(map); thread_map__put(map);
/* test dummy pid */ /* test dummy pid */
...@@ -44,7 +44,7 @@ int test__thread_map(int subtest __maybe_unused) ...@@ -44,7 +44,7 @@ int test__thread_map(int subtest __maybe_unused)
thread_map__comm(map, 0) && thread_map__comm(map, 0) &&
!strcmp(thread_map__comm(map, 0), "dummy")); !strcmp(thread_map__comm(map, 0), "dummy"));
TEST_ASSERT_VAL("wrong refcnt", TEST_ASSERT_VAL("wrong refcnt",
atomic_read(&map->refcnt) == 1); refcount_read(&map->refcnt) == 1);
thread_map__put(map); thread_map__put(map);
return 0; return 0;
} }
...@@ -71,7 +71,7 @@ static int process_event(struct perf_tool *tool __maybe_unused, ...@@ -71,7 +71,7 @@ static int process_event(struct perf_tool *tool __maybe_unused,
thread_map__comm(threads, 0) && thread_map__comm(threads, 0) &&
!strcmp(thread_map__comm(threads, 0), NAME)); !strcmp(thread_map__comm(threads, 0), NAME));
TEST_ASSERT_VAL("wrong refcnt", TEST_ASSERT_VAL("wrong refcnt",
atomic_read(&threads->refcnt) == 1); refcount_read(&threads->refcnt) == 1);
thread_map__put(threads); thread_map__put(threads);
return 0; return 0;
} }
......
...@@ -43,7 +43,7 @@ int test__thread_mg_share(int subtest __maybe_unused) ...@@ -43,7 +43,7 @@ int test__thread_mg_share(int subtest __maybe_unused)
leader && t1 && t2 && t3 && other); leader && t1 && t2 && t3 && other);
mg = leader->mg; 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 the map groups pointer is shared */
TEST_ASSERT_VAL("map groups don't match", mg == t1->mg); TEST_ASSERT_VAL("map groups don't match", mg == t1->mg);
...@@ -71,25 +71,25 @@ int test__thread_mg_share(int subtest __maybe_unused) ...@@ -71,25 +71,25 @@ int test__thread_mg_share(int subtest __maybe_unused)
machine__remove_thread(machine, other_leader); machine__remove_thread(machine, other_leader);
other_mg = other->mg; 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); TEST_ASSERT_VAL("map groups don't match", other_mg == other_leader->mg);
/* release thread group */ /* release thread group */
thread__put(leader); 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); 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); 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); thread__put(t3);
/* release other group */ /* release other group */
thread__put(other_leader); 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); thread__put(other);
......
...@@ -127,19 +127,19 @@ static int add_cgroup(struct perf_evlist *evlist, char *str) ...@@ -127,19 +127,19 @@ static int add_cgroup(struct perf_evlist *evlist, char *str)
goto found; goto found;
n++; n++;
} }
if (atomic_read(&cgrp->refcnt) == 0) if (refcount_read(&cgrp->refcnt) == 0)
free(cgrp); free(cgrp);
return -1; return -1;
found: found:
atomic_inc(&cgrp->refcnt); refcount_inc(&cgrp->refcnt);
counter->cgrp = cgrp; counter->cgrp = cgrp;
return 0; return 0;
} }
void close_cgroup(struct cgroup_sel *cgrp) 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); close(cgrp->fd);
zfree(&cgrp->name); zfree(&cgrp->name);
free(cgrp); free(cgrp);
......
#ifndef __CGROUP_H__ #ifndef __CGROUP_H__
#define __CGROUP_H__ #define __CGROUP_H__
#include <linux/atomic.h> #include <linux/refcount.h>
struct option; struct option;
struct cgroup_sel { struct cgroup_sel {
char *name; char *name;
int fd; int fd;
atomic_t refcnt; refcount_t refcnt;
}; };
......
...@@ -3,10 +3,4 @@ ...@@ -3,10 +3,4 @@
unsigned long perf_event_open_cloexec_flag(void); 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 */ #endif /* __PERF_CLOEXEC_H */
...@@ -2,12 +2,12 @@ ...@@ -2,12 +2,12 @@
#include "util.h" #include "util.h"
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <linux/atomic.h> #include <linux/refcount.h>
struct comm_str { struct comm_str {
char *str; char *str;
struct rb_node rb_node; struct rb_node rb_node;
atomic_t refcnt; refcount_t refcnt;
}; };
/* Should perhaps be moved to struct machine */ /* Should perhaps be moved to struct machine */
...@@ -16,13 +16,13 @@ static struct rb_root comm_str_root; ...@@ -16,13 +16,13 @@ static struct rb_root comm_str_root;
static struct comm_str *comm_str__get(struct comm_str *cs) static struct comm_str *comm_str__get(struct comm_str *cs)
{ {
if (cs) if (cs)
atomic_inc(&cs->refcnt); refcount_inc(&cs->refcnt);
return cs; return cs;
} }
static void comm_str__put(struct comm_str *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); rb_erase(&cs->rb_node, &comm_str_root);
zfree(&cs->str); zfree(&cs->str);
free(cs); free(cs);
...@@ -43,7 +43,7 @@ static struct comm_str *comm_str__alloc(const char *str) ...@@ -43,7 +43,7 @@ static struct comm_str *comm_str__alloc(const char *str)
return NULL; return NULL;
} }
atomic_set(&cs->refcnt, 0); refcount_set(&cs->refcnt, 1);
return cs; return cs;
} }
...@@ -61,7 +61,7 @@ static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root) ...@@ -61,7 +61,7 @@ static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root)
cmp = strcmp(str, iter->str); cmp = strcmp(str, iter->str);
if (!cmp) if (!cmp)
return iter; return comm_str__get(iter);
if (cmp < 0) if (cmp < 0)
p = &(*p)->rb_left; p = &(*p)->rb_left;
...@@ -95,8 +95,6 @@ struct comm *comm__new(const char *str, u64 timestamp, bool exec) ...@@ -95,8 +95,6 @@ struct comm *comm__new(const char *str, u64 timestamp, bool exec)
return NULL; return NULL;
} }
comm_str__get(comm->comm_str);
return comm; return comm;
} }
...@@ -108,7 +106,6 @@ int comm__override(struct comm *comm, const char *str, u64 timestamp, bool exec) ...@@ -108,7 +106,6 @@ int comm__override(struct comm *comm, const char *str, u64 timestamp, bool exec)
if (!new) if (!new)
return -ENOMEM; return -ENOMEM;
comm_str__get(new);
comm_str__put(old); comm_str__put(old);
comm->comm_str = new; comm->comm_str = new;
comm->start = timestamp; comm->start = timestamp;
......
...@@ -29,7 +29,7 @@ static struct cpu_map *cpu_map__default_new(void) ...@@ -29,7 +29,7 @@ static struct cpu_map *cpu_map__default_new(void)
cpus->map[i] = i; cpus->map[i] = i;
cpus->nr = nr_cpus; cpus->nr = nr_cpus;
atomic_set(&cpus->refcnt, 1); refcount_set(&cpus->refcnt, 1);
} }
return cpus; return cpus;
...@@ -43,7 +43,7 @@ static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus) ...@@ -43,7 +43,7 @@ static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus)
if (cpus != NULL) { if (cpus != NULL) {
cpus->nr = nr_cpus; cpus->nr = nr_cpus;
memcpy(cpus->map, tmp_cpus, payload_size); memcpy(cpus->map, tmp_cpus, payload_size);
atomic_set(&cpus->refcnt, 1); refcount_set(&cpus->refcnt, 1);
} }
return cpus; return cpus;
...@@ -252,7 +252,7 @@ struct cpu_map *cpu_map__dummy_new(void) ...@@ -252,7 +252,7 @@ struct cpu_map *cpu_map__dummy_new(void)
if (cpus != NULL) { if (cpus != NULL) {
cpus->nr = 1; cpus->nr = 1;
cpus->map[0] = -1; cpus->map[0] = -1;
atomic_set(&cpus->refcnt, 1); refcount_set(&cpus->refcnt, 1);
} }
return cpus; return cpus;
...@@ -269,7 +269,7 @@ struct cpu_map *cpu_map__empty_new(int nr) ...@@ -269,7 +269,7 @@ struct cpu_map *cpu_map__empty_new(int nr)
for (i = 0; i < nr; i++) for (i = 0; i < nr; i++)
cpus->map[i] = -1; cpus->map[i] = -1;
atomic_set(&cpus->refcnt, 1); refcount_set(&cpus->refcnt, 1);
} }
return cpus; return cpus;
...@@ -278,7 +278,7 @@ struct cpu_map *cpu_map__empty_new(int nr) ...@@ -278,7 +278,7 @@ struct cpu_map *cpu_map__empty_new(int nr)
static void cpu_map__delete(struct cpu_map *map) static void cpu_map__delete(struct cpu_map *map)
{ {
if (map) { if (map) {
WARN_ONCE(atomic_read(&map->refcnt) != 0, WARN_ONCE(refcount_read(&map->refcnt) != 0,
"cpu_map refcnt unbalanced\n"); "cpu_map refcnt unbalanced\n");
free(map); free(map);
} }
...@@ -287,13 +287,13 @@ static void cpu_map__delete(struct cpu_map *map) ...@@ -287,13 +287,13 @@ static void cpu_map__delete(struct cpu_map *map)
struct cpu_map *cpu_map__get(struct cpu_map *map) struct cpu_map *cpu_map__get(struct cpu_map *map)
{ {
if (map) if (map)
atomic_inc(&map->refcnt); refcount_inc(&map->refcnt);
return map; return map;
} }
void cpu_map__put(struct cpu_map *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); cpu_map__delete(map);
} }
...@@ -357,7 +357,7 @@ int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, ...@@ -357,7 +357,7 @@ int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res,
/* ensure we process id in increasing order */ /* ensure we process id in increasing order */
qsort(c->map, c->nr, sizeof(int), cmp_ids); qsort(c->map, c->nr, sizeof(int), cmp_ids);
atomic_set(&c->refcnt, 1); refcount_set(&c->refcnt, 1);
*res = c; *res = c;
return 0; return 0;
} }
...@@ -673,3 +673,49 @@ size_t cpu_map__snprint(struct cpu_map *map, char *buf, size_t size) ...@@ -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); pr_debug("cpumask list: %s\n", buf);
return ret; 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 @@ ...@@ -3,13 +3,13 @@
#include <stdio.h> #include <stdio.h>
#include <stdbool.h> #include <stdbool.h>
#include <linux/atomic.h> #include <linux/refcount.h>
#include "perf.h" #include "perf.h"
#include "util/debug.h" #include "util/debug.h"
struct cpu_map { struct cpu_map {
atomic_t refcnt; refcount_t refcnt;
int nr; int nr;
int map[]; int map[];
}; };
...@@ -20,6 +20,7 @@ struct cpu_map *cpu_map__dummy_new(void); ...@@ -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__new_data(struct cpu_map_data *data);
struct cpu_map *cpu_map__read(FILE *file); 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(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); size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
int cpu_map__get_socket_id(int cpu); int cpu_map__get_socket_id(int cpu);
int cpu_map__get_socket(struct cpu_map *map, int idx, void *data); int cpu_map__get_socket(struct cpu_map *map, int idx, void *data);
......
...@@ -1109,7 +1109,7 @@ struct dso *dso__new(const char *name) ...@@ -1109,7 +1109,7 @@ struct dso *dso__new(const char *name)
INIT_LIST_HEAD(&dso->node); INIT_LIST_HEAD(&dso->node);
INIT_LIST_HEAD(&dso->data.open_entry); INIT_LIST_HEAD(&dso->data.open_entry);
pthread_mutex_init(&dso->lock, NULL); pthread_mutex_init(&dso->lock, NULL);
atomic_set(&dso->refcnt, 1); refcount_set(&dso->refcnt, 1);
} }
return dso; return dso;
...@@ -1147,13 +1147,13 @@ void dso__delete(struct dso *dso) ...@@ -1147,13 +1147,13 @@ void dso__delete(struct dso *dso)
struct dso *dso__get(struct dso *dso) struct dso *dso__get(struct dso *dso)
{ {
if (dso) if (dso)
atomic_inc(&dso->refcnt); refcount_inc(&dso->refcnt);
return dso; return dso;
} }
void dso__put(struct dso *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); dso__delete(dso);
} }
......
#ifndef __PERF_DSO #ifndef __PERF_DSO
#define __PERF_DSO #define __PERF_DSO
#include <linux/atomic.h> #include <linux/refcount.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/rbtree.h> #include <linux/rbtree.h>
#include <sys/types.h> #include <sys/types.h>
...@@ -187,7 +187,7 @@ struct dso { ...@@ -187,7 +187,7 @@ struct dso {
void *priv; void *priv;
u64 db_id; u64 db_id;
}; };
atomic_t refcnt; refcount_t refcnt;
char name[0]; char name[0];
}; };
......
...@@ -777,7 +777,7 @@ union perf_event *perf_mmap__read_forward(struct perf_mmap *md, bool check_messu ...@@ -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. * Check if event was unmapped due to a POLLHUP/POLLERR.
*/ */
if (!atomic_read(&md->refcnt)) if (!refcount_read(&md->refcnt))
return NULL; return NULL;
head = perf_mmap__read_head(md); head = perf_mmap__read_head(md);
...@@ -794,7 +794,7 @@ perf_mmap__read_backward(struct perf_mmap *md) ...@@ -794,7 +794,7 @@ perf_mmap__read_backward(struct perf_mmap *md)
/* /*
* Check if event was unmapped due to a POLLHUP/POLLERR. * Check if event was unmapped due to a POLLHUP/POLLERR.
*/ */
if (!atomic_read(&md->refcnt)) if (!refcount_read(&md->refcnt))
return NULL; return NULL;
head = perf_mmap__read_head(md); head = perf_mmap__read_head(md);
...@@ -856,7 +856,7 @@ void perf_mmap__read_catchup(struct perf_mmap *md) ...@@ -856,7 +856,7 @@ void perf_mmap__read_catchup(struct perf_mmap *md)
{ {
u64 head; u64 head;
if (!atomic_read(&md->refcnt)) if (!refcount_read(&md->refcnt))
return; return;
head = perf_mmap__read_head(md); head = perf_mmap__read_head(md);
...@@ -875,14 +875,14 @@ static bool perf_mmap__empty(struct perf_mmap *md) ...@@ -875,14 +875,14 @@ static bool perf_mmap__empty(struct perf_mmap *md)
static void perf_mmap__get(struct perf_mmap *map) 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) 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); perf_mmap__munmap(md);
} }
...@@ -894,7 +894,7 @@ void perf_mmap__consume(struct perf_mmap *md, bool overwrite) ...@@ -894,7 +894,7 @@ void perf_mmap__consume(struct perf_mmap *md, bool overwrite)
perf_mmap__write_tail(md, old); 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); perf_mmap__put(md);
} }
...@@ -937,7 +937,7 @@ static void perf_mmap__munmap(struct perf_mmap *map) ...@@ -937,7 +937,7 @@ static void perf_mmap__munmap(struct perf_mmap *map)
munmap(map->base, perf_mmap__mmap_len(map)); munmap(map->base, perf_mmap__mmap_len(map));
map->base = NULL; map->base = NULL;
map->fd = -1; map->fd = -1;
atomic_set(&map->refcnt, 0); refcount_set(&map->refcnt, 0);
} }
auxtrace_mmap__munmap(&map->auxtrace_mmap); auxtrace_mmap__munmap(&map->auxtrace_mmap);
} }
...@@ -974,8 +974,19 @@ static struct perf_mmap *perf_evlist__alloc_mmap(struct perf_evlist *evlist) ...@@ -974,8 +974,19 @@ static struct perf_mmap *perf_evlist__alloc_mmap(struct perf_evlist *evlist)
if (!map) if (!map)
return NULL; return NULL;
for (i = 0; i < evlist->nr_mmaps; i++) for (i = 0; i < evlist->nr_mmaps; i++) {
map[i].fd = -1; 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; return map;
} }
...@@ -1001,7 +1012,7 @@ static int perf_mmap__mmap(struct perf_mmap *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 * evlist layer can't just drop it when filtering events in
* perf_evlist__filter_pollfd(). * perf_evlist__filter_pollfd().
*/ */
atomic_set(&map->refcnt, 2); refcount_set(&map->refcnt, 2);
map->prev = 0; map->prev = 0;
map->mask = mp->mask; map->mask = mp->mask;
map->base = mmap(NULL, perf_mmap__mmap_len(map), mp->prot, map->base = mmap(NULL, perf_mmap__mmap_len(map), mp->prot,
......
#ifndef __PERF_EVLIST_H #ifndef __PERF_EVLIST_H
#define __PERF_EVLIST_H 1 #define __PERF_EVLIST_H 1
#include <linux/atomic.h> #include <linux/refcount.h>
#include <linux/list.h> #include <linux/list.h>
#include <api/fd/array.h> #include <api/fd/array.h>
#include <stdio.h> #include <stdio.h>
...@@ -29,7 +29,7 @@ struct perf_mmap { ...@@ -29,7 +29,7 @@ struct perf_mmap {
void *base; void *base;
int mask; int mask;
int fd; int fd;
atomic_t refcnt; refcount_t refcnt;
u64 prev; u64 prev;
struct auxtrace_mmap auxtrace_mmap; struct auxtrace_mmap auxtrace_mmap;
char event_copy[PERF_SAMPLE_MAX_SIZE] __attribute__((aligned(8))); char event_copy[PERF_SAMPLE_MAX_SIZE] __attribute__((aligned(8)));
......
...@@ -57,6 +57,7 @@ enum hist_column { ...@@ -57,6 +57,7 @@ enum hist_column {
HISTC_SRCLINE_FROM, HISTC_SRCLINE_FROM,
HISTC_SRCLINE_TO, HISTC_SRCLINE_TO,
HISTC_TRACE, HISTC_TRACE,
HISTC_SYM_SIZE,
HISTC_NR_COLS, /* Last entry */ HISTC_NR_COLS, /* Last entry */
}; };
......
...@@ -39,6 +39,8 @@ static void intel_pt_insn_decoder(struct insn *insn, ...@@ -39,6 +39,8 @@ static void intel_pt_insn_decoder(struct insn *insn,
enum intel_pt_insn_branch branch = INTEL_PT_BR_NO_BRANCH; enum intel_pt_insn_branch branch = INTEL_PT_BR_NO_BRANCH;
int ext; int ext;
intel_pt_insn->rel = 0;
if (insn_is_avx(insn)) { if (insn_is_avx(insn)) {
intel_pt_insn->op = INTEL_PT_OP_OTHER; intel_pt_insn->op = INTEL_PT_OP_OTHER;
intel_pt_insn->branch = INTEL_PT_BR_NO_BRANCH; intel_pt_insn->branch = INTEL_PT_BR_NO_BRANCH;
......
...@@ -1439,7 +1439,7 @@ static void __machine__remove_thread(struct machine *machine, struct thread *th, ...@@ -1439,7 +1439,7 @@ static void __machine__remove_thread(struct machine *machine, struct thread *th,
if (machine->last_match == th) if (machine->last_match == th)
machine->last_match = NULL; machine->last_match = NULL;
BUG_ON(atomic_read(&th->refcnt) == 0); BUG_ON(refcount_read(&th->refcnt) == 0);
if (lock) if (lock)
pthread_rwlock_wrlock(&machine->threads_lock); pthread_rwlock_wrlock(&machine->threads_lock);
rb_erase_init(&th->rb_node, &machine->threads); rb_erase_init(&th->rb_node, &machine->threads);
......
...@@ -141,7 +141,7 @@ void map__init(struct map *map, enum map_type type, ...@@ -141,7 +141,7 @@ void map__init(struct map *map, enum map_type type,
RB_CLEAR_NODE(&map->rb_node); RB_CLEAR_NODE(&map->rb_node);
map->groups = NULL; map->groups = NULL;
map->erange_warned = false; 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, struct map *map__new(struct machine *machine, u64 start, u64 len,
...@@ -255,7 +255,7 @@ void map__delete(struct map *map) ...@@ -255,7 +255,7 @@ void map__delete(struct map *map)
void map__put(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); map__delete(map);
} }
...@@ -354,7 +354,7 @@ struct map *map__clone(struct map *from) ...@@ -354,7 +354,7 @@ struct map *map__clone(struct map *from)
struct map *map = memdup(from, sizeof(*map)); struct map *map = memdup(from, sizeof(*map));
if (map != NULL) { if (map != NULL) {
atomic_set(&map->refcnt, 1); refcount_set(&map->refcnt, 1);
RB_CLEAR_NODE(&map->rb_node); RB_CLEAR_NODE(&map->rb_node);
dso__get(map->dso); dso__get(map->dso);
map->groups = NULL; map->groups = NULL;
...@@ -485,7 +485,7 @@ void map_groups__init(struct map_groups *mg, struct machine *machine) ...@@ -485,7 +485,7 @@ void map_groups__init(struct map_groups *mg, struct machine *machine)
maps__init(&mg->maps[i]); maps__init(&mg->maps[i]);
} }
mg->machine = machine; mg->machine = machine;
atomic_set(&mg->refcnt, 1); refcount_set(&mg->refcnt, 1);
} }
static void __maps__purge(struct maps *maps) static void __maps__purge(struct maps *maps)
...@@ -547,7 +547,7 @@ void map_groups__delete(struct map_groups *mg) ...@@ -547,7 +547,7 @@ void map_groups__delete(struct map_groups *mg)
void map_groups__put(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); map_groups__delete(mg);
} }
......
#ifndef __PERF_MAP_H #ifndef __PERF_MAP_H
#define __PERF_MAP_H #define __PERF_MAP_H
#include <linux/atomic.h> #include <linux/refcount.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/rbtree.h> #include <linux/rbtree.h>
...@@ -51,7 +51,7 @@ struct map { ...@@ -51,7 +51,7 @@ struct map {
struct dso *dso; struct dso *dso;
struct map_groups *groups; struct map_groups *groups;
atomic_t refcnt; refcount_t refcnt;
}; };
struct kmap { struct kmap {
...@@ -67,7 +67,7 @@ struct maps { ...@@ -67,7 +67,7 @@ struct maps {
struct map_groups { struct map_groups {
struct maps maps[MAP__NR_TYPES]; struct maps maps[MAP__NR_TYPES];
struct machine *machine; struct machine *machine;
atomic_t refcnt; refcount_t refcnt;
}; };
struct map_groups *map_groups__new(struct machine *machine); struct map_groups *map_groups__new(struct machine *machine);
...@@ -77,7 +77,7 @@ bool map_groups__empty(struct map_groups *mg); ...@@ -77,7 +77,7 @@ bool map_groups__empty(struct map_groups *mg);
static inline struct map_groups *map_groups__get(struct map_groups *mg) static inline struct map_groups *map_groups__get(struct map_groups *mg)
{ {
if (mg) if (mg)
atomic_inc(&mg->refcnt); refcount_inc(&mg->refcnt);
return mg; return mg;
} }
...@@ -150,7 +150,7 @@ struct map *map__clone(struct map *map); ...@@ -150,7 +150,7 @@ struct map *map__clone(struct map *map);
static inline struct map *map__get(struct map *map) static inline struct map *map__get(struct map *map)
{ {
if (map) if (map)
atomic_inc(&map->refcnt); refcount_inc(&map->refcnt);
return map; return map;
} }
......
...@@ -316,8 +316,9 @@ __add_event(struct list_head *list, int *idx, ...@@ -316,8 +316,9 @@ __add_event(struct list_head *list, int *idx,
return NULL; return NULL;
(*idx)++; (*idx)++;
evsel->cpus = cpu_map__get(cpus); evsel->cpus = cpu_map__get(cpus);
evsel->own_cpus = cpu_map__get(cpus); evsel->own_cpus = cpu_map__get(cpus);
evsel->system_wide = !!cpus;
if (name) if (name)
evsel->name = strdup(name); evsel->name = strdup(name);
......
...@@ -70,7 +70,7 @@ static void print_both_open_warning(int kerr, int uerr) ...@@ -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]; char buf[PATH_MAX];
int ret; int ret;
...@@ -92,12 +92,12 @@ static int open_probe_events(const char *trace_file, bool readwrite) ...@@ -92,12 +92,12 @@ static int open_probe_events(const char *trace_file, bool readwrite)
static int open_kprobe_events(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) 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) int probe_file__open(int flag)
...@@ -899,6 +899,7 @@ bool probe_type_is_available(enum probe_type type) ...@@ -899,6 +899,7 @@ bool probe_type_is_available(enum probe_type type)
size_t len = 0; size_t len = 0;
bool target_line = false; bool target_line = false;
bool ret = probe_type_table[type].avail; bool ret = probe_type_table[type].avail;
int fd;
if (type >= PROBE_TYPE_END) if (type >= PROBE_TYPE_END)
return false; return false;
...@@ -906,14 +907,16 @@ bool probe_type_is_available(enum probe_type type) ...@@ -906,14 +907,16 @@ bool probe_type_is_available(enum probe_type type)
if (ret || probe_type_table[type].checked) if (ret || probe_type_table[type].checked)
return ret; return ret;
if (asprintf(&buf, "%s/README", tracing_path) < 0) fd = open_trace_file("README", false);
if (fd < 0)
return ret; return ret;
fp = fopen(buf, "r"); fp = fdopen(fd, "r");
if (!fp) if (!fp) {
goto end; close(fd);
return ret;
}
zfree(&buf);
while (getline(&buf, &len, fp) > 0 && !ret) { while (getline(&buf, &len, fp) > 0 && !ret) {
if (!target_line) { if (!target_line) {
target_line = !!strstr(buf, " type: "); target_line = !!strstr(buf, " type: ");
...@@ -928,7 +931,6 @@ bool probe_type_is_available(enum probe_type type) ...@@ -928,7 +931,6 @@ bool probe_type_is_available(enum probe_type type)
probe_type_table[type].avail = ret; probe_type_table[type].avail = ret;
fclose(fp); fclose(fp);
end:
free(buf); free(buf);
return ret; return ret;
......
...@@ -35,6 +35,7 @@ enum probe_type { ...@@ -35,6 +35,7 @@ enum probe_type {
/* probe-file.c depends on libelf */ /* probe-file.c depends on libelf */
#ifdef HAVE_LIBELF_SUPPORT #ifdef HAVE_LIBELF_SUPPORT
int open_trace_file(const char *trace_file, bool readwrite);
int probe_file__open(int flag); int probe_file__open(int flag);
int probe_file__open_both(int *kfd, int *ufd, int flag); int probe_file__open_both(int *kfd, int *ufd, int flag);
struct strlist *probe_file__get_namelist(int fd); struct strlist *probe_file__get_namelist(int fd);
......
...@@ -1396,6 +1396,46 @@ struct sort_entry sort_transaction = { ...@@ -1396,6 +1396,46 @@ struct sort_entry sort_transaction = {
.se_width_idx = HISTC_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 { struct sort_dimension {
const char *name; const char *name;
struct sort_entry *entry; struct sort_entry *entry;
...@@ -1418,6 +1458,7 @@ static struct sort_dimension common_sort_dimensions[] = { ...@@ -1418,6 +1458,7 @@ static struct sort_dimension common_sort_dimensions[] = {
DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight), DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
DIM(SORT_TRANSACTION, "transaction", sort_transaction), DIM(SORT_TRANSACTION, "transaction", sort_transaction),
DIM(SORT_TRACE, "trace", sort_trace), DIM(SORT_TRACE, "trace", sort_trace),
DIM(SORT_SYM_SIZE, "symbol_size", sort_sym_size),
}; };
#undef DIM #undef DIM
......
...@@ -211,6 +211,7 @@ enum sort_type { ...@@ -211,6 +211,7 @@ enum sort_type {
SORT_GLOBAL_WEIGHT, SORT_GLOBAL_WEIGHT,
SORT_TRANSACTION, SORT_TRANSACTION,
SORT_TRACE, SORT_TRACE,
SORT_SYM_SIZE,
/* branch stack specific sort keys */ /* branch stack specific sort keys */
__SORT_BRANCH_STACK, __SORT_BRANCH_STACK,
......
...@@ -53,7 +53,7 @@ struct thread *thread__new(pid_t pid, pid_t tid) ...@@ -53,7 +53,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
goto err_thread; goto err_thread;
list_add(&comm->list, &thread->comm_list); list_add(&comm->list, &thread->comm_list);
atomic_set(&thread->refcnt, 1); refcount_set(&thread->refcnt, 1);
RB_CLEAR_NODE(&thread->rb_node); RB_CLEAR_NODE(&thread->rb_node);
} }
...@@ -88,13 +88,13 @@ void thread__delete(struct thread *thread) ...@@ -88,13 +88,13 @@ void thread__delete(struct thread *thread)
struct thread *thread__get(struct thread *thread) struct thread *thread__get(struct thread *thread)
{ {
if (thread) if (thread)
atomic_inc(&thread->refcnt); refcount_inc(&thread->refcnt);
return thread; return thread;
} }
void thread__put(struct thread *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 * Remove it from the dead_threads list, as last reference
* is gone. * is gone.
......
#ifndef __PERF_THREAD_H #ifndef __PERF_THREAD_H
#define __PERF_THREAD_H #define __PERF_THREAD_H
#include <linux/atomic.h> #include <linux/refcount.h>
#include <linux/rbtree.h> #include <linux/rbtree.h>
#include <linux/list.h> #include <linux/list.h>
#include <unistd.h> #include <unistd.h>
...@@ -23,7 +23,7 @@ struct thread { ...@@ -23,7 +23,7 @@ struct thread {
pid_t tid; pid_t tid;
pid_t ppid; pid_t ppid;
int cpu; int cpu;
atomic_t refcnt; refcount_t refcnt;
char shortname[3]; char shortname[3];
bool comm_set; bool comm_set;
int comm_len; int comm_len;
......
...@@ -66,7 +66,7 @@ struct thread_map *thread_map__new_by_pid(pid_t pid) ...@@ -66,7 +66,7 @@ struct thread_map *thread_map__new_by_pid(pid_t pid)
for (i = 0; i < items; i++) for (i = 0; i < items; i++)
thread_map__set_pid(threads, i, atoi(namelist[i]->d_name)); thread_map__set_pid(threads, i, atoi(namelist[i]->d_name));
threads->nr = items; threads->nr = items;
atomic_set(&threads->refcnt, 1); refcount_set(&threads->refcnt, 1);
} }
for (i=0; i<items; i++) for (i=0; i<items; i++)
...@@ -83,7 +83,7 @@ struct thread_map *thread_map__new_by_tid(pid_t tid) ...@@ -83,7 +83,7 @@ struct thread_map *thread_map__new_by_tid(pid_t tid)
if (threads != NULL) { if (threads != NULL) {
thread_map__set_pid(threads, 0, tid); thread_map__set_pid(threads, 0, tid);
threads->nr = 1; threads->nr = 1;
atomic_set(&threads->refcnt, 1); refcount_set(&threads->refcnt, 1);
} }
return threads; return threads;
...@@ -105,7 +105,7 @@ struct thread_map *thread_map__new_by_uid(uid_t uid) ...@@ -105,7 +105,7 @@ struct thread_map *thread_map__new_by_uid(uid_t uid)
goto out_free_threads; goto out_free_threads;
threads->nr = 0; threads->nr = 0;
atomic_set(&threads->refcnt, 1); refcount_set(&threads->refcnt, 1);
while ((dirent = readdir(proc)) != NULL) { while ((dirent = readdir(proc)) != NULL) {
char *end; char *end;
...@@ -235,7 +235,7 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str) ...@@ -235,7 +235,7 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str)
out: out:
strlist__delete(slist); strlist__delete(slist);
if (threads) if (threads)
atomic_set(&threads->refcnt, 1); refcount_set(&threads->refcnt, 1);
return threads; return threads;
out_free_namelist: out_free_namelist:
...@@ -255,7 +255,7 @@ struct thread_map *thread_map__new_dummy(void) ...@@ -255,7 +255,7 @@ struct thread_map *thread_map__new_dummy(void)
if (threads != NULL) { if (threads != NULL) {
thread_map__set_pid(threads, 0, -1); thread_map__set_pid(threads, 0, -1);
threads->nr = 1; threads->nr = 1;
atomic_set(&threads->refcnt, 1); refcount_set(&threads->refcnt, 1);
} }
return threads; return threads;
} }
...@@ -300,7 +300,7 @@ struct thread_map *thread_map__new_by_tid_str(const char *tid_str) ...@@ -300,7 +300,7 @@ struct thread_map *thread_map__new_by_tid_str(const char *tid_str)
} }
out: out:
if (threads) if (threads)
atomic_set(&threads->refcnt, 1); refcount_set(&threads->refcnt, 1);
return threads; return threads;
out_free_threads: out_free_threads:
...@@ -326,7 +326,7 @@ static void thread_map__delete(struct thread_map *threads) ...@@ -326,7 +326,7 @@ static void thread_map__delete(struct thread_map *threads)
if (threads) { if (threads) {
int i; int i;
WARN_ONCE(atomic_read(&threads->refcnt) != 0, WARN_ONCE(refcount_read(&threads->refcnt) != 0,
"thread map refcnt unbalanced\n"); "thread map refcnt unbalanced\n");
for (i = 0; i < threads->nr; i++) for (i = 0; i < threads->nr; i++)
free(thread_map__comm(threads, i)); free(thread_map__comm(threads, i));
...@@ -337,13 +337,13 @@ static void thread_map__delete(struct thread_map *threads) ...@@ -337,13 +337,13 @@ static void thread_map__delete(struct thread_map *threads)
struct thread_map *thread_map__get(struct thread_map *map) struct thread_map *thread_map__get(struct thread_map *map)
{ {
if (map) if (map)
atomic_inc(&map->refcnt); refcount_inc(&map->refcnt);
return map; return map;
} }
void thread_map__put(struct thread_map *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); thread_map__delete(map);
} }
...@@ -423,7 +423,7 @@ static void thread_map__copy_event(struct thread_map *threads, ...@@ -423,7 +423,7 @@ static void thread_map__copy_event(struct thread_map *threads,
threads->map[i].comm = strndup(event->entries[i].comm, 16); 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) struct thread_map *thread_map__new_event(struct thread_map_event *event)
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdio.h> #include <stdio.h>
#include <linux/atomic.h> #include <linux/refcount.h>
struct thread_map_data { struct thread_map_data {
pid_t pid; pid_t pid;
...@@ -11,7 +11,7 @@ struct thread_map_data { ...@@ -11,7 +11,7 @@ struct thread_map_data {
}; };
struct thread_map { struct thread_map {
atomic_t refcnt; refcount_t refcnt;
int nr; int nr;
struct thread_map_data map[]; struct thread_map_data map[];
}; };
......
...@@ -355,8 +355,8 @@ void print_binary(unsigned char *data, size_t len, ...@@ -355,8 +355,8 @@ void print_binary(unsigned char *data, size_t len,
size_t bytes_per_line, print_binary_t printer, size_t bytes_per_line, print_binary_t printer,
void *extra); void *extra);
#if !defined(__GLIBC__) && !defined(__ANDROID__) #ifndef HAVE_SCHED_GETCPU_SUPPORT
extern int sched_getcpu(void); int sched_getcpu(void);
#endif #endif
int is_printable_array(char *p, unsigned int len); int is_printable_array(char *p, unsigned int len);
......
...@@ -43,6 +43,15 @@ ifneq ($(CC), clang) ...@@ -43,6 +43,15 @@ ifneq ($(CC), clang)
EXTRA_WARNINGS += -Wstrict-aliasing=3 EXTRA_WARNINGS += -Wstrict-aliasing=3
endif 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) ifneq ($(findstring $(MAKEFLAGS), w),w)
PRINT_DIR = --no-print-directory PRINT_DIR = --no-print-directory
else else
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment