Commit 94ac003b authored by Ingo Molnar's avatar Ingo Molnar

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

Merge tag 'perf-core-for-mingo' 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:

User visible changes:

  - Warn if given uprobe event accesses memory on older kernel (Masami Hiramatsu)

  - 'perf record' Documentation fixes (Namhyung Kim)

  - Report unsupported events properly in 'perf stat' (Suzuki K. Poulose)

Infrastructure changes:

  - Avoid FORK after COMM when synthesizing records for pre-existing threads (Arnaldo Carvalho de Melo)

  - Reference count struct thread (Arnaldo Carvalho de Melo)

  - Don't keep the session around in 'perf sched', thread refcounting removes that need (Arnaldo Carvalho de Melo)

  - Initialize cpu set in pthread_attr_setaffinity_np() feature test (Adrian Hunter)

  - Only include tsc file for x86 (David Ahern)

  - Compare JOBS to 0 after grep (David Ahern)

  - Improve feature detection messages (Ingo Molnar)

  - Revert "perf: Remove the extra validity check on nr_pages" (Kan Liang)

  - Remove bias offset to find probe point by address (Masami Hiramatsu)

  - Fix build error on ARCH=i386/x86_64/sparc64 (Namhyung Kim)
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 788b94ba ae536acf
...@@ -223,10 +223,22 @@ static unsigned long ...@@ -223,10 +223,22 @@ static unsigned long
__recover_probed_insn(kprobe_opcode_t *buf, unsigned long addr) __recover_probed_insn(kprobe_opcode_t *buf, unsigned long addr)
{ {
struct kprobe *kp; struct kprobe *kp;
unsigned long faddr;
kp = get_kprobe((void *)addr); kp = get_kprobe((void *)addr);
/* There is no probe, return original address */ faddr = ftrace_location(addr);
if (!kp) /*
* Addresses inside the ftrace location are refused by
* arch_check_ftrace_location(). Something went terribly wrong
* if such an address is checked here.
*/
if (WARN_ON(faddr && faddr != addr))
return 0UL;
/*
* Use the current code if it is not modified by Kprobe
* and it cannot be modified by ftrace.
*/
if (!kp && !faddr)
return addr; return addr;
/* /*
...@@ -236,13 +248,22 @@ __recover_probed_insn(kprobe_opcode_t *buf, unsigned long addr) ...@@ -236,13 +248,22 @@ __recover_probed_insn(kprobe_opcode_t *buf, unsigned long addr)
* that instruction. In that case, we can't recover the instruction * that instruction. In that case, we can't recover the instruction
* from the kp->ainsn.insn. * from the kp->ainsn.insn.
* *
* On the other hand, kp->opcode has a copy of the first byte of * On the other hand, in case on normal Kprobe, kp->opcode has a copy
* the probed instruction, which is overwritten by int3. And * of the first byte of the probed instruction, which is overwritten
* the instruction at kp->addr is not modified by kprobes except * by int3. And the instruction at kp->addr is not modified by kprobes
* for the first byte, we can recover the original instruction * except for the first byte, we can recover the original instruction
* from it and kp->opcode. * from it and kp->opcode.
*
* In case of Kprobes using ftrace, we do not have a copy of
* the original instruction. In fact, the ftrace location might
* be modified at anytime and even could be in an inconsistent state.
* Fortunately, we know that the original code is the ideal 5-byte
* long NOP.
*/ */
memcpy(buf, kp->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); memcpy(buf, (void *)addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
if (faddr)
memcpy(buf, ideal_nops[NOP_ATOMIC5], 5);
else
buf[0] = kp->opcode; buf[0] = kp->opcode;
return (unsigned long)buf; return (unsigned long)buf;
} }
...@@ -251,6 +272,7 @@ __recover_probed_insn(kprobe_opcode_t *buf, unsigned long addr) ...@@ -251,6 +272,7 @@ __recover_probed_insn(kprobe_opcode_t *buf, unsigned long addr)
* Recover the probed instruction at addr for further analysis. * Recover the probed instruction at addr for further analysis.
* Caller must lock kprobes by kprobe_mutex, or disable preemption * Caller must lock kprobes by kprobe_mutex, or disable preemption
* for preventing to release referencing kprobes. * for preventing to release referencing kprobes.
* Returns zero if the instruction can not get recovered.
*/ */
unsigned long recover_probed_instruction(kprobe_opcode_t *buf, unsigned long addr) unsigned long recover_probed_instruction(kprobe_opcode_t *buf, unsigned long addr)
{ {
...@@ -285,6 +307,8 @@ static int can_probe(unsigned long paddr) ...@@ -285,6 +307,8 @@ static int can_probe(unsigned long paddr)
* normally used, we just go through if there is no kprobe. * normally used, we just go through if there is no kprobe.
*/ */
__addr = recover_probed_instruction(buf, addr); __addr = recover_probed_instruction(buf, addr);
if (!__addr)
return 0;
kernel_insn_init(&insn, (void *)__addr, MAX_INSN_SIZE); kernel_insn_init(&insn, (void *)__addr, MAX_INSN_SIZE);
insn_get_length(&insn); insn_get_length(&insn);
...@@ -333,6 +357,8 @@ int __copy_instruction(u8 *dest, u8 *src) ...@@ -333,6 +357,8 @@ int __copy_instruction(u8 *dest, u8 *src)
unsigned long recovered_insn = unsigned long recovered_insn =
recover_probed_instruction(buf, (unsigned long)src); recover_probed_instruction(buf, (unsigned long)src);
if (!recovered_insn)
return 0;
kernel_insn_init(&insn, (void *)recovered_insn, MAX_INSN_SIZE); kernel_insn_init(&insn, (void *)recovered_insn, MAX_INSN_SIZE);
insn_get_length(&insn); insn_get_length(&insn);
/* Another subsystem puts a breakpoint, failed to recover */ /* Another subsystem puts a breakpoint, failed to recover */
......
...@@ -259,6 +259,8 @@ static int can_optimize(unsigned long paddr) ...@@ -259,6 +259,8 @@ static int can_optimize(unsigned long paddr)
*/ */
return 0; return 0;
recovered_insn = recover_probed_instruction(buf, addr); recovered_insn = recover_probed_instruction(buf, addr);
if (!recovered_insn)
return 0;
kernel_insn_init(&insn, (void *)recovered_insn, MAX_INSN_SIZE); kernel_insn_init(&insn, (void *)recovered_insn, MAX_INSN_SIZE);
insn_get_length(&insn); insn_get_length(&insn);
/* Another subsystem puts a breakpoint */ /* Another subsystem puts a breakpoint */
......
...@@ -4446,7 +4446,7 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -4446,7 +4446,7 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma)
* If we have rb pages ensure they're a power-of-two number, so we * If we have rb pages ensure they're a power-of-two number, so we
* can do bitmasks instead of modulo. * can do bitmasks instead of modulo.
*/ */
if (!is_power_of_2(nr_pages)) if (nr_pages != 0 && !is_power_of_2(nr_pages))
return -EINVAL; return -EINVAL;
if (vma_size != PAGE_SIZE * (1 + nr_pages)) if (vma_size != PAGE_SIZE * (1 + nr_pages))
......
PERF-CFLAGS PERF-CFLAGS
PERF-GUI-VARS PERF-GUI-VARS
PERF-VERSION-FILE PERF-VERSION-FILE
PERF-FEATURES
perf perf
perf-read-vdso32 perf-read-vdso32
perf-read-vdsox32 perf-read-vdsox32
......
...@@ -55,6 +55,11 @@ OPTIONS ...@@ -55,6 +55,11 @@ OPTIONS
If you want to profile write accesses in [0x1000~1008), just set If you want to profile write accesses in [0x1000~1008), just set
'mem:0x1000/8:w'. 'mem:0x1000/8:w'.
- a group of events surrounded by a pair of brace ("{event1,event2,...}").
Each event is separated by commas and the group should be quoted to
prevent the shell interpretation. You also need to use --group on
"perf report" to view group events together.
--filter=<filter>:: --filter=<filter>::
Event filter. Event filter.
...@@ -62,9 +67,6 @@ OPTIONS ...@@ -62,9 +67,6 @@ OPTIONS
--all-cpus:: --all-cpus::
System-wide collection from all CPUs. System-wide collection from all CPUs.
-l::
Scale counter values.
-p:: -p::
--pid=:: --pid=::
Record events on existing process ID (comma separated list). Record events on existing process ID (comma separated list).
...@@ -107,6 +109,10 @@ OPTIONS ...@@ -107,6 +109,10 @@ OPTIONS
specification with appended unit character - B/K/M/G. The specification with appended unit character - B/K/M/G. The
size is rounded up to have nearest pages power of two value. size is rounded up to have nearest pages power of two value.
--group::
Put all events in a single event group. This precedes the --event
option and remains only for backward compatibility. See --event.
-g:: -g::
Enables call-graph (stack chain/backtrace) recording. Enables call-graph (stack chain/backtrace) recording.
......
...@@ -25,7 +25,7 @@ unexport MAKEFLAGS ...@@ -25,7 +25,7 @@ unexport MAKEFLAGS
# #
ifeq ($(JOBS),) ifeq ($(JOBS),)
JOBS := $(shell grep -c ^processor /proc/cpuinfo 2>/dev/null) JOBS := $(shell grep -c ^processor /proc/cpuinfo 2>/dev/null)
ifeq ($(JOBS),) ifeq ($(JOBS),0)
JOBS := 1 JOBS := 1
endif endif
endif endif
......
...@@ -289,7 +289,7 @@ static u64 do_memcpy_cycle(const struct routine *r, size_t len, bool prefault) ...@@ -289,7 +289,7 @@ static u64 do_memcpy_cycle(const struct routine *r, size_t len, bool prefault)
memcpy_t fn = r->fn.memcpy; memcpy_t fn = r->fn.memcpy;
int i; int i;
memcpy_alloc_mem(&src, &dst, len); memcpy_alloc_mem(&dst, &src, len);
if (prefault) if (prefault)
fn(dst, src, len); fn(dst, src, len);
...@@ -312,7 +312,7 @@ static double do_memcpy_gettimeofday(const struct routine *r, size_t len, ...@@ -312,7 +312,7 @@ static double do_memcpy_gettimeofday(const struct routine *r, size_t len,
void *src = NULL, *dst = NULL; void *src = NULL, *dst = NULL;
int i; int i;
memcpy_alloc_mem(&src, &dst, len); memcpy_alloc_mem(&dst, &src, len);
if (prefault) if (prefault)
fn(dst, src, len); fn(dst, src, len);
......
...@@ -831,7 +831,7 @@ static int thread_atoms_insert(struct perf_sched *sched, struct thread *thread) ...@@ -831,7 +831,7 @@ static int thread_atoms_insert(struct perf_sched *sched, struct thread *thread)
return -1; return -1;
} }
atoms->thread = thread; atoms->thread = thread__get(thread);
INIT_LIST_HEAD(&atoms->work_list); INIT_LIST_HEAD(&atoms->work_list);
__thread_latency_insert(&sched->atom_root, atoms, &sched->cmp_pid); __thread_latency_insert(&sched->atom_root, atoms, &sched->cmp_pid);
return 0; return 0;
...@@ -1439,8 +1439,7 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_ ...@@ -1439,8 +1439,7 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_
return err; return err;
} }
static int perf_sched__read_events(struct perf_sched *sched, static int perf_sched__read_events(struct perf_sched *sched)
struct perf_session **psession)
{ {
const struct perf_evsel_str_handler handlers[] = { const struct perf_evsel_str_handler handlers[] = {
{ "sched:sched_switch", process_sched_switch_event, }, { "sched:sched_switch", process_sched_switch_event, },
...@@ -1454,6 +1453,7 @@ static int perf_sched__read_events(struct perf_sched *sched, ...@@ -1454,6 +1453,7 @@ static int perf_sched__read_events(struct perf_sched *sched,
.path = input_name, .path = input_name,
.mode = PERF_DATA_MODE_READ, .mode = PERF_DATA_MODE_READ,
}; };
int rc = -1;
session = perf_session__new(&file, false, &sched->tool); session = perf_session__new(&file, false, &sched->tool);
if (session == NULL) { if (session == NULL) {
...@@ -1478,16 +1478,10 @@ static int perf_sched__read_events(struct perf_sched *sched, ...@@ -1478,16 +1478,10 @@ static int perf_sched__read_events(struct perf_sched *sched,
sched->nr_lost_chunks = session->evlist->stats.nr_events[PERF_RECORD_LOST]; sched->nr_lost_chunks = session->evlist->stats.nr_events[PERF_RECORD_LOST];
} }
if (psession) rc = 0;
*psession = session;
else
perf_session__delete(session);
return 0;
out_delete: out_delete:
perf_session__delete(session); perf_session__delete(session);
return -1; return rc;
} }
static void print_bad_events(struct perf_sched *sched) static void print_bad_events(struct perf_sched *sched)
...@@ -1515,12 +1509,10 @@ static void print_bad_events(struct perf_sched *sched) ...@@ -1515,12 +1509,10 @@ static void print_bad_events(struct perf_sched *sched)
static int perf_sched__lat(struct perf_sched *sched) static int perf_sched__lat(struct perf_sched *sched)
{ {
struct rb_node *next; struct rb_node *next;
struct perf_session *session;
setup_pager(); setup_pager();
/* save session -- references to threads are held in work_list */ if (perf_sched__read_events(sched))
if (perf_sched__read_events(sched, &session))
return -1; return -1;
perf_sched__sort_lat(sched); perf_sched__sort_lat(sched);
...@@ -1537,6 +1529,7 @@ static int perf_sched__lat(struct perf_sched *sched) ...@@ -1537,6 +1529,7 @@ static int perf_sched__lat(struct perf_sched *sched)
work_list = rb_entry(next, struct work_atoms, node); work_list = rb_entry(next, struct work_atoms, node);
output_lat_thread(sched, work_list); output_lat_thread(sched, work_list);
next = rb_next(next); next = rb_next(next);
thread__zput(work_list->thread);
} }
printf(" -----------------------------------------------------------------------------------------------------------------\n"); printf(" -----------------------------------------------------------------------------------------------------------------\n");
...@@ -1548,7 +1541,6 @@ static int perf_sched__lat(struct perf_sched *sched) ...@@ -1548,7 +1541,6 @@ static int perf_sched__lat(struct perf_sched *sched)
print_bad_events(sched); print_bad_events(sched);
printf("\n"); printf("\n");
perf_session__delete(session);
return 0; return 0;
} }
...@@ -1557,7 +1549,7 @@ static int perf_sched__map(struct perf_sched *sched) ...@@ -1557,7 +1549,7 @@ static int perf_sched__map(struct perf_sched *sched)
sched->max_cpu = sysconf(_SC_NPROCESSORS_CONF); sched->max_cpu = sysconf(_SC_NPROCESSORS_CONF);
setup_pager(); setup_pager();
if (perf_sched__read_events(sched, NULL)) if (perf_sched__read_events(sched))
return -1; return -1;
print_bad_events(sched); print_bad_events(sched);
return 0; return 0;
...@@ -1572,7 +1564,7 @@ static int perf_sched__replay(struct perf_sched *sched) ...@@ -1572,7 +1564,7 @@ static int perf_sched__replay(struct perf_sched *sched)
test_calibrations(sched); test_calibrations(sched);
if (perf_sched__read_events(sched, NULL)) if (perf_sched__read_events(sched))
return -1; return -1;
printf("nr_run_events: %ld\n", sched->nr_run_events); printf("nr_run_events: %ld\n", sched->nr_run_events);
......
...@@ -510,6 +510,9 @@ static int read_counter(struct perf_evsel *counter) ...@@ -510,6 +510,9 @@ static int read_counter(struct perf_evsel *counter)
int ncpus = perf_evsel__nr_cpus(counter); int ncpus = perf_evsel__nr_cpus(counter);
int cpu, thread; int cpu, thread;
if (!counter->supported)
return -ENOENT;
if (counter->system_wide) if (counter->system_wide)
nthreads = 1; nthreads = 1;
...@@ -1285,7 +1288,7 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix) ...@@ -1285,7 +1288,7 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
if (prefix) if (prefix)
fprintf(output, "%s", prefix); fprintf(output, "%s", prefix);
if (scaled == -1) { if (scaled == -1 || !counter->supported) {
fprintf(output, "%*s%s", fprintf(output, "%*s%s",
csv_output ? 0 : 18, csv_output ? 0 : 18,
counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
......
...@@ -1741,7 +1741,10 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, ...@@ -1741,7 +1741,10 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
} else } else
ttrace->entry_pending = true; ttrace->entry_pending = true;
trace->current = thread; if (trace->current != thread) {
thread__put(trace->current);
trace->current = thread__get(thread);
}
return 0; return 0;
} }
...@@ -2274,6 +2277,8 @@ static int trace__run(struct trace *trace, int argc, const char **argv) ...@@ -2274,6 +2277,8 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
} }
out_disable: out_disable:
thread__zput(trace->current);
perf_evlist__disable(evlist); perf_evlist__disable(evlist);
if (!err) { if (!err) {
......
...@@ -531,7 +531,7 @@ else ...@@ -531,7 +531,7 @@ else
ifneq ($(feature-libperl), 1) ifneq ($(feature-libperl), 1)
CFLAGS += -DNO_LIBPERL CFLAGS += -DNO_LIBPERL
NO_LIBPERL := 1 NO_LIBPERL := 1
msg := $(warning Missing perl devel files. Disabling perl scripting support, consider installing perl-ExtUtils-Embed); msg := $(warning Missing perl devel files. Disabling perl scripting support, please install perl-ExtUtils-Embed/libperl-dev);
else else
LDFLAGS += $(PERL_EMBED_LDFLAGS) LDFLAGS += $(PERL_EMBED_LDFLAGS)
EXTLIBS += $(PERL_EMBED_LIBADD) EXTLIBS += $(PERL_EMBED_LIBADD)
...@@ -548,22 +548,21 @@ endif ...@@ -548,22 +548,21 @@ endif
disable-python = $(eval $(disable-python_code)) disable-python = $(eval $(disable-python_code))
define disable-python_code define disable-python_code
CFLAGS += -DNO_LIBPYTHON CFLAGS += -DNO_LIBPYTHON
$(if $(1),$(warning No $(1) was found)) $(warning $1)
$(warning Python support will not be built)
NO_LIBPYTHON := 1 NO_LIBPYTHON := 1
endef endef
ifdef NO_LIBPYTHON ifdef NO_LIBPYTHON
$(call disable-python) $(call disable-python,Python support disabled by user)
else else
ifndef PYTHON ifndef PYTHON
$(call disable-python,python interpreter) $(call disable-python,No python interpreter was found: disables Python support - please install python-devel/python-dev)
else else
PYTHON_WORD := $(call shell-wordify,$(PYTHON)) PYTHON_WORD := $(call shell-wordify,$(PYTHON))
ifndef PYTHON_CONFIG ifndef PYTHON_CONFIG
$(call disable-python,python-config tool) $(call disable-python,No 'python-config' tool was found: disables Python support - please install python-devel/python-dev)
else else
PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG)) PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG))
...@@ -575,7 +574,7 @@ else ...@@ -575,7 +574,7 @@ else
FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
ifneq ($(feature-libpython), 1) ifneq ($(feature-libpython), 1)
$(call disable-python,Python.h (for Python 2.x)) $(call disable-python,No 'Python.h' (for Python 2.x support) was found: disables Python support - please install python-devel/python-dev)
else else
ifneq ($(feature-libpython-version), 1) ifneq ($(feature-libpython-version), 1)
...@@ -636,7 +635,7 @@ else ...@@ -636,7 +635,7 @@ else
EXTLIBS += -liberty EXTLIBS += -liberty
CFLAGS += -DHAVE_CPLUS_DEMANGLE_SUPPORT CFLAGS += -DHAVE_CPLUS_DEMANGLE_SUPPORT
else else
msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling) msg := $(warning No bfd.h/libbfd found, please install binutils-dev[el]/zlib-static/libiberty-dev to gain symbol demangling)
CFLAGS += -DNO_DEMANGLE CFLAGS += -DNO_DEMANGLE
endif endif
endif endif
...@@ -707,7 +706,7 @@ endif ...@@ -707,7 +706,7 @@ endif
ifndef NO_LIBBABELTRACE ifndef NO_LIBBABELTRACE
ifeq ($(feature-libbabeltrace), 0) ifeq ($(feature-libbabeltrace), 0)
msg := $(warning No libbabeltrace found, disables 'perf data' CTF format support, please install libbabeltrace-devel/libbabeltrace-ctf-dev); msg := $(warning No libbabeltrace found, disables 'perf data' CTF format support, please install libbabeltrace-dev[el]/libbabeltrace-ctf-dev);
NO_LIBBABELTRACE := 1 NO_LIBBABELTRACE := 1
else else
CFLAGS += -DHAVE_LIBBABELTRACE_SUPPORT $(LIBBABELTRACE_CFLAGS) CFLAGS += -DHAVE_LIBBABELTRACE_SUPPORT $(LIBBABELTRACE_CFLAGS)
......
ifndef ARCH
ARCH := $(shell uname -m 2>/dev/null || echo not)
endif
uname_M := $(shell uname -m 2>/dev/null || echo not) ARCH := $(shell echo $(ARCH) | sed -e s/i.86/x86/ -e s/x86_64/x86/ \
-e s/sun4u/sparc/ -e s/sparc64/sparc/ \
RAW_ARCH := $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
-e s/arm.*/arm/ -e s/sa110/arm/ \ -e s/arm.*/arm/ -e s/sa110/arm/ \
-e s/s390x/s390/ -e s/parisc64/parisc/ \ -e s/s390x/s390/ -e s/parisc64/parisc/ \
-e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
-e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ \ -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ \
-e s/tile.*/tile/ ) -e s/tile.*/tile/ )
# Additional ARCH settings for x86
ifeq ($(RAW_ARCH),i386)
ARCH ?= x86
endif
ifeq ($(RAW_ARCH),x86_64)
ARCH ?= x86
ifneq (, $(findstring m32,$(CFLAGS)))
RAW_ARCH := x86_32
endif
endif
ARCH ?= $(RAW_ARCH)
LP64 := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1) LP64 := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1)
ifeq ($(LP64), 1) ifeq ($(LP64), 1)
IS_64_BIT := 1 IS_64_BIT := 1
......
...@@ -39,24 +39,24 @@ PKG_CONFIG := $(CROSS_COMPILE)pkg-config ...@@ -39,24 +39,24 @@ PKG_CONFIG := $(CROSS_COMPILE)pkg-config
all: $(FILES) all: $(FILES)
BUILD = $(CC) $(CFLAGS) -o $(OUTPUT)$@ $(patsubst %.bin,%.c,$@) $(LDFLAGS) BUILD = $(CC) $(CFLAGS) -Wall -Werror -o $(OUTPUT)$@ $(patsubst %.bin,%.c,$@) $(LDFLAGS)
############################### ###############################
test-all.bin: test-all.bin:
$(BUILD) -Werror -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl -lz -lbabeltrace $(BUILD) -fstack-protector-all -O2 -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl -lz -lbabeltrace
test-hello.bin: test-hello.bin:
$(BUILD) $(BUILD)
test-pthread-attr-setaffinity-np.bin: test-pthread-attr-setaffinity-np.bin:
$(BUILD) -D_GNU_SOURCE -Werror -lpthread $(BUILD) -D_GNU_SOURCE -lpthread
test-stackprotector-all.bin: test-stackprotector-all.bin:
$(BUILD) -Werror -fstack-protector-all $(BUILD) -fstack-protector-all
test-fortify-source.bin: test-fortify-source.bin:
$(BUILD) -O2 -Werror -D_FORTIFY_SOURCE=2 $(BUILD) -O2 -D_FORTIFY_SOURCE=2
test-bionic.bin: test-bionic.bin:
$(BUILD) $(BUILD)
...@@ -119,10 +119,10 @@ test-libbfd.bin: ...@@ -119,10 +119,10 @@ test-libbfd.bin:
$(BUILD) -DPACKAGE='"perf"' -lbfd -lz -liberty -ldl $(BUILD) -DPACKAGE='"perf"' -lbfd -lz -liberty -ldl
test-liberty.bin: test-liberty.bin:
$(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty $(CC) -Wall -Werror -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty
test-liberty-z.bin: test-liberty-z.bin:
$(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty -lz $(CC) -Wall -Werror -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty -lz
test-cplus-demangle.bin: test-cplus-demangle.bin:
$(BUILD) -liberty $(BUILD) -liberty
...@@ -140,7 +140,7 @@ test-libbabeltrace.bin: ...@@ -140,7 +140,7 @@ test-libbabeltrace.bin:
$(BUILD) # -lbabeltrace provided by $(FEATURE_CHECK_LDFLAGS-libbabeltrace) $(BUILD) # -lbabeltrace provided by $(FEATURE_CHECK_LDFLAGS-libbabeltrace)
test-sync-compare-and-swap.bin: test-sync-compare-and-swap.bin:
$(BUILD) -Werror $(BUILD)
test-compile-32.bin: test-compile-32.bin:
$(CC) -m32 -o $(OUTPUT)$@ test-compile.c $(CC) -m32 -o $(OUTPUT)$@ test-compile.c
......
#include <stdint.h> #include <stdint.h>
#include <pthread.h> #include <pthread.h>
#include <sched.h>
int main(void) int main(void)
{ {
int ret = 0; int ret = 0;
pthread_attr_t thread_attr; pthread_attr_t thread_attr;
cpu_set_t cs;
pthread_attr_init(&thread_attr); pthread_attr_init(&thread_attr);
/* don't care abt exact args, just the API itself in libpthread */ CPU_ZERO(&cs);
ret = pthread_attr_setaffinity_np(&thread_attr, 0, NULL);
ret = pthread_attr_setaffinity_np(&thread_attr, sizeof(cs), &cs);
return ret; return ret;
} }
...@@ -175,6 +175,5 @@ _ge-abspath = $(if $(is-executable),$(1)) ...@@ -175,6 +175,5 @@ _ge-abspath = $(if $(is-executable),$(1))
define get-executable-or-default define get-executable-or-default
$(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2))) $(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2)))
endef endef
_ge_attempt = $(if $(get-executable),$(get-executable),$(_gea_warn)$(call _gea_err,$(2))) _ge_attempt = $(if $(get-executable),$(get-executable),$(call _gea_err,$(2)))
_gea_warn = $(warning The path '$(1)' is not executable.)
_gea_err = $(if $(1),$(error Please set '$(1)' appropriately)) _gea_err = $(if $(1),$(error Please set '$(1)' appropriately))
...@@ -1467,7 +1467,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -1467,7 +1467,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
perf_hpp__set_user_width(symbol_conf.col_width_list_str); perf_hpp__set_user_width(symbol_conf.col_width_list_str);
while (1) { while (1) {
const struct thread *thread = NULL; struct thread *thread = NULL;
const struct dso *dso = NULL; const struct dso *dso = NULL;
int choice = 0, int choice = 0,
annotate = -2, zoom_dso = -2, zoom_thread = -2, annotate = -2, zoom_dso = -2, zoom_thread = -2,
...@@ -1754,13 +1754,13 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -1754,13 +1754,13 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
pstack__remove(fstack, &browser->hists->thread_filter); pstack__remove(fstack, &browser->hists->thread_filter);
zoom_out_thread: zoom_out_thread:
ui_helpline__pop(); ui_helpline__pop();
browser->hists->thread_filter = NULL; thread__zput(browser->hists->thread_filter);
perf_hpp__set_elide(HISTC_THREAD, false); perf_hpp__set_elide(HISTC_THREAD, false);
} else { } else {
ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
thread->comm_set ? thread__comm_str(thread) : "", thread->comm_set ? thread__comm_str(thread) : "",
thread->tid); thread->tid);
browser->hists->thread_filter = thread; browser->hists->thread_filter = thread__get(thread);
perf_hpp__set_elide(HISTC_THREAD, false); perf_hpp__set_elide(HISTC_THREAD, false);
pstack__push(fstack, &browser->hists->thread_filter); pstack__push(fstack, &browser->hists->thread_filter);
} }
......
...@@ -71,7 +71,7 @@ libperf-y += stat.o ...@@ -71,7 +71,7 @@ libperf-y += stat.o
libperf-y += record.o libperf-y += record.o
libperf-y += srcline.o libperf-y += srcline.o
libperf-y += data.o libperf-y += data.o
libperf-y += tsc.o libperf-$(CONFIG_X86) += tsc.o
libperf-y += cloexec.o libperf-y += cloexec.o
libperf-y += thread-stack.o libperf-y += thread-stack.o
......
...@@ -61,8 +61,9 @@ static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused, ...@@ -61,8 +61,9 @@ static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused,
if (thread) { if (thread) {
rb_erase(&thread->rb_node, &machine->threads); rb_erase(&thread->rb_node, &machine->threads);
machine->last_match = NULL; if (machine->last_match == thread)
thread__delete(thread); thread__zput(machine->last_match);
thread__put(thread);
} }
return 0; return 0;
......
...@@ -25,6 +25,10 @@ static int perf_flag_probe(void) ...@@ -25,6 +25,10 @@ static int perf_flag_probe(void)
if (cpu < 0) if (cpu < 0)
cpu = 0; cpu = 0;
/*
* Using -1 for the pid is a workaround to avoid gratuitous jump label
* changes.
*/
while (1) { while (1) {
/* check cloexec flag */ /* check cloexec flag */
fd = sys_perf_event_open(&attr, pid, cpu, -1, fd = sys_perf_event_open(&attr, pid, cpu, -1,
...@@ -47,16 +51,24 @@ static int perf_flag_probe(void) ...@@ -47,16 +51,24 @@ static int perf_flag_probe(void)
err, strerror_r(err, sbuf, sizeof(sbuf))); err, strerror_r(err, sbuf, sizeof(sbuf)));
/* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */ /* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */
while (1) {
fd = sys_perf_event_open(&attr, pid, cpu, -1, 0); fd = sys_perf_event_open(&attr, pid, cpu, -1, 0);
if (fd < 0 && pid == -1 && errno == EACCES) {
pid = 0;
continue;
}
break;
}
err = errno; err = errno;
if (fd >= 0)
close(fd);
if (WARN_ONCE(fd < 0 && err != EBUSY, if (WARN_ONCE(fd < 0 && err != EBUSY,
"perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n", "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n",
err, strerror_r(err, sbuf, sizeof(sbuf)))) err, strerror_r(err, sbuf, sizeof(sbuf))))
return -1; return -1;
close(fd);
return 0; return 0;
} }
......
...@@ -95,9 +95,7 @@ static pid_t perf_event__get_comm_tgid(pid_t pid, char *comm, size_t len) ...@@ -95,9 +95,7 @@ static pid_t perf_event__get_comm_tgid(pid_t pid, char *comm, size_t len)
return tgid; return tgid;
} }
static pid_t perf_event__synthesize_comm(struct perf_tool *tool, static pid_t perf_event__prepare_comm(union perf_event *event, pid_t pid,
union perf_event *event, pid_t pid,
perf_event__handler_t process,
struct machine *machine) struct machine *machine)
{ {
size_t size; size_t size;
...@@ -124,6 +122,19 @@ static pid_t perf_event__synthesize_comm(struct perf_tool *tool, ...@@ -124,6 +122,19 @@ static pid_t perf_event__synthesize_comm(struct perf_tool *tool,
(sizeof(event->comm.comm) - size) + (sizeof(event->comm.comm) - size) +
machine->id_hdr_size); machine->id_hdr_size);
event->comm.tid = pid; event->comm.tid = pid;
out:
return tgid;
}
static pid_t perf_event__synthesize_comm(struct perf_tool *tool,
union perf_event *event, pid_t pid,
perf_event__handler_t process,
struct machine *machine)
{
pid_t tgid = perf_event__prepare_comm(event, pid, machine);
if (tgid == -1)
goto out;
if (process(tool, event, &synth_sample, machine) != 0) if (process(tool, event, &synth_sample, machine) != 0)
return -1; return -1;
...@@ -139,7 +150,6 @@ static int perf_event__synthesize_fork(struct perf_tool *tool, ...@@ -139,7 +150,6 @@ static int perf_event__synthesize_fork(struct perf_tool *tool,
{ {
memset(&event->fork, 0, sizeof(event->fork) + machine->id_hdr_size); memset(&event->fork, 0, sizeof(event->fork) + machine->id_hdr_size);
/* this is really a clone event but we use fork to synthesize it */
event->fork.ppid = tgid; event->fork.ppid = tgid;
event->fork.ptid = tgid; event->fork.ptid = tgid;
event->fork.pid = tgid; event->fork.pid = tgid;
...@@ -368,19 +378,23 @@ static int __event__synthesize_thread(union perf_event *comm_event, ...@@ -368,19 +378,23 @@ static int __event__synthesize_thread(union perf_event *comm_event,
if (*end) if (*end)
continue; continue;
tgid = perf_event__synthesize_comm(tool, comm_event, _pid, tgid = perf_event__prepare_comm(comm_event, _pid, machine);
process, machine);
if (tgid == -1) if (tgid == -1)
return -1; return -1;
if (perf_event__synthesize_fork(tool, fork_event, _pid, tgid,
process, machine) < 0)
return -1;
/*
* Send the prepared comm event
*/
if (process(tool, comm_event, &synth_sample, machine) != 0)
return -1;
if (_pid == pid) { if (_pid == pid) {
/* process the parent's maps too */ /* process the parent's maps too */
rc = perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, rc = perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
process, machine, mmap_data); process, machine, mmap_data);
} else {
/* only fork the tid's map, to save time */
rc = perf_event__synthesize_fork(tool, fork_event, _pid, tgid,
process, machine);
} }
if (rc) if (rc)
......
...@@ -28,7 +28,7 @@ struct perf_mmap { ...@@ -28,7 +28,7 @@ struct perf_mmap {
int mask; int mask;
int refcnt; int refcnt;
unsigned int prev; unsigned int prev;
char event_copy[PERF_SAMPLE_MAX_SIZE]; char event_copy[PERF_SAMPLE_MAX_SIZE] __attribute__((aligned(8)));
}; };
struct perf_evlist { struct perf_evlist {
......
...@@ -355,6 +355,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template, ...@@ -355,6 +355,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template,
callchain_init(he->callchain); callchain_init(he->callchain);
INIT_LIST_HEAD(&he->pairs.node); INIT_LIST_HEAD(&he->pairs.node);
thread__get(he->thread);
} }
return he; return he;
...@@ -941,6 +942,7 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) ...@@ -941,6 +942,7 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
void hist_entry__delete(struct hist_entry *he) void hist_entry__delete(struct hist_entry *he)
{ {
thread__zput(he->thread);
zfree(&he->branch_info); zfree(&he->branch_info);
zfree(&he->mem_info); zfree(&he->mem_info);
zfree(&he->stat_acc); zfree(&he->stat_acc);
......
...@@ -60,7 +60,7 @@ struct hists { ...@@ -60,7 +60,7 @@ struct hists {
struct rb_root entries_collapsed; struct rb_root entries_collapsed;
u64 nr_entries; u64 nr_entries;
u64 nr_non_filtered_entries; u64 nr_non_filtered_entries;
const struct thread *thread_filter; struct thread *thread_filter;
const struct dso *dso_filter; const struct dso *dso_filter;
const char *uid_filter_str; const char *uid_filter_str;
const char *symbol_filter_str; const char *symbol_filter_str;
......
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
#include "unwind.h" #include "unwind.h"
#include "linux/hash.h" #include "linux/hash.h"
static void machine__remove_thread(struct machine *machine, struct thread *th);
static void dsos__init(struct dsos *dsos) static void dsos__init(struct dsos *dsos)
{ {
INIT_LIST_HEAD(&dsos->head); INIT_LIST_HEAD(&dsos->head);
...@@ -89,16 +91,6 @@ static void dsos__delete(struct dsos *dsos) ...@@ -89,16 +91,6 @@ static void dsos__delete(struct dsos *dsos)
} }
} }
void machine__delete_dead_threads(struct machine *machine)
{
struct thread *n, *t;
list_for_each_entry_safe(t, n, &machine->dead_threads, node) {
list_del(&t->node);
thread__delete(t);
}
}
void machine__delete_threads(struct machine *machine) void machine__delete_threads(struct machine *machine)
{ {
struct rb_node *nd = rb_first(&machine->threads); struct rb_node *nd = rb_first(&machine->threads);
...@@ -106,9 +98,8 @@ void machine__delete_threads(struct machine *machine) ...@@ -106,9 +98,8 @@ void machine__delete_threads(struct machine *machine)
while (nd) { while (nd) {
struct thread *t = rb_entry(nd, struct thread, rb_node); struct thread *t = rb_entry(nd, struct thread, rb_node);
rb_erase(&t->rb_node, &machine->threads);
nd = rb_next(nd); nd = rb_next(nd);
thread__delete(t); machine__remove_thread(machine, t);
} }
} }
...@@ -361,17 +352,21 @@ static struct thread *__machine__findnew_thread(struct machine *machine, ...@@ -361,17 +352,21 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
* the full rbtree: * the full rbtree:
*/ */
th = machine->last_match; th = machine->last_match;
if (th && th->tid == tid) { if (th != NULL) {
if (th->tid == tid) {
machine__update_thread_pid(machine, th, pid); machine__update_thread_pid(machine, th, pid);
return th; return th;
} }
thread__zput(machine->last_match);
}
while (*p != NULL) { while (*p != NULL) {
parent = *p; parent = *p;
th = rb_entry(parent, struct thread, rb_node); th = rb_entry(parent, struct thread, rb_node);
if (th->tid == tid) { if (th->tid == tid) {
machine->last_match = th; machine->last_match = thread__get(th);
machine__update_thread_pid(machine, th, pid); machine__update_thread_pid(machine, th, pid);
return th; return th;
} }
...@@ -403,8 +398,11 @@ static struct thread *__machine__findnew_thread(struct machine *machine, ...@@ -403,8 +398,11 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
thread__delete(th); thread__delete(th);
return NULL; return NULL;
} }
/*
machine->last_match = th; * It is now in the rbtree, get a ref
*/
thread__get(th);
machine->last_match = thread__get(th);
} }
return th; return th;
...@@ -1238,13 +1236,17 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event ...@@ -1238,13 +1236,17 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
static void machine__remove_thread(struct machine *machine, struct thread *th) static void machine__remove_thread(struct machine *machine, struct thread *th)
{ {
machine->last_match = NULL; if (machine->last_match == th)
thread__zput(machine->last_match);
rb_erase(&th->rb_node, &machine->threads); rb_erase(&th->rb_node, &machine->threads);
/* /*
* We may have references to this thread, for instance in some hist_entry * Move it first to the dead_threads list, then drop the reference,
* instances, so just move them to a separate list. * if this is the last reference, then the thread__delete destructor
* will be called and we will remove it from the dead_threads list.
*/ */
list_add_tail(&th->node, &machine->dead_threads); list_add_tail(&th->node, &machine->dead_threads);
thread__put(th);
} }
int machine__process_fork_event(struct machine *machine, union perf_event *event, int machine__process_fork_event(struct machine *machine, union perf_event *event,
......
...@@ -118,7 +118,6 @@ void machines__set_comm_exec(struct machines *machines, bool comm_exec); ...@@ -118,7 +118,6 @@ void machines__set_comm_exec(struct machines *machines, bool comm_exec);
struct machine *machine__new_host(void); struct machine *machine__new_host(void);
int machine__init(struct machine *machine, const char *root_dir, pid_t pid); int machine__init(struct machine *machine, const char *root_dir, pid_t pid);
void machine__exit(struct machine *machine); void machine__exit(struct machine *machine);
void machine__delete_dead_threads(struct machine *machine);
void machine__delete_threads(struct machine *machine); void machine__delete_threads(struct machine *machine);
void machine__delete(struct machine *machine); void machine__delete(struct machine *machine);
......
...@@ -2199,6 +2199,27 @@ static int get_new_event_name(char *buf, size_t len, const char *base, ...@@ -2199,6 +2199,27 @@ static int get_new_event_name(char *buf, size_t len, const char *base,
return ret; return ret;
} }
/* Warn if the current kernel's uprobe implementation is old */
static void warn_uprobe_event_compat(struct probe_trace_event *tev)
{
int i;
char *buf = synthesize_probe_trace_command(tev);
/* Old uprobe event doesn't support memory dereference */
if (!tev->uprobes || tev->nargs == 0 || !buf)
goto out;
for (i = 0; i < tev->nargs; i++)
if (strglobmatch(tev->args[i].value, "[$@+-]*")) {
pr_warning("Please upgrade your kernel to at least "
"3.14 to have access to feature %s\n",
tev->args[i].value);
break;
}
out:
free(buf);
}
static int __add_probe_trace_events(struct perf_probe_event *pev, static int __add_probe_trace_events(struct perf_probe_event *pev,
struct probe_trace_event *tevs, struct probe_trace_event *tevs,
int ntevs, bool allow_suffix) int ntevs, bool allow_suffix)
...@@ -2295,6 +2316,8 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, ...@@ -2295,6 +2316,8 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
*/ */
allow_suffix = true; allow_suffix = true;
} }
if (ret == -EINVAL && pev->uprobes)
warn_uprobe_event_compat(tev);
/* Note that it is possible to skip all events because of blacklist */ /* Note that it is possible to skip all events because of blacklist */
if (ret >= 0 && tev->event) { if (ret >= 0 && tev->event) {
......
...@@ -1345,11 +1345,8 @@ int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr, ...@@ -1345,11 +1345,8 @@ int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr,
const char *fname = NULL, *func = NULL, *basefunc = NULL, *tmp; const char *fname = NULL, *func = NULL, *basefunc = NULL, *tmp;
int baseline = 0, lineno = 0, ret = 0; int baseline = 0, lineno = 0, ret = 0;
/* Adjust address with bias */
addr += dbg->bias;
/* Find cu die */ /* Find cu die */
if (!dwarf_addrdie(dbg->dbg, (Dwarf_Addr)addr - dbg->bias, &cudie)) { if (!dwarf_addrdie(dbg->dbg, (Dwarf_Addr)addr, &cudie)) {
pr_warning("Failed to find debug information for address %lx\n", pr_warning("Failed to find debug information for address %lx\n",
addr); addr);
ret = -EINVAL; ret = -EINVAL;
......
...@@ -138,11 +138,6 @@ struct perf_session *perf_session__new(struct perf_data_file *file, ...@@ -138,11 +138,6 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
return NULL; return NULL;
} }
static void perf_session__delete_dead_threads(struct perf_session *session)
{
machine__delete_dead_threads(&session->machines.host);
}
static void perf_session__delete_threads(struct perf_session *session) static void perf_session__delete_threads(struct perf_session *session)
{ {
machine__delete_threads(&session->machines.host); machine__delete_threads(&session->machines.host);
...@@ -167,7 +162,6 @@ static void perf_session_env__delete(struct perf_session_env *env) ...@@ -167,7 +162,6 @@ static void perf_session_env__delete(struct perf_session_env *env)
void perf_session__delete(struct perf_session *session) void perf_session__delete(struct perf_session *session)
{ {
perf_session__destroy_kernel_maps(session); perf_session__destroy_kernel_maps(session);
perf_session__delete_dead_threads(session);
perf_session__delete_threads(session); perf_session__delete_threads(session);
perf_session_env__delete(&session->header.env); perf_session_env__delete(&session->header.env);
machines__exit(&session->machines); machines__exit(&session->machines);
......
...@@ -11,6 +11,11 @@ ...@@ -11,6 +11,11 @@
#include <symbol/kallsyms.h> #include <symbol/kallsyms.h>
#include "debug.h" #include "debug.h"
#ifndef EM_AARCH64
#define EM_AARCH64 183 /* ARM 64 bit */
#endif
#ifdef HAVE_CPLUS_DEMANGLE_SUPPORT #ifdef HAVE_CPLUS_DEMANGLE_SUPPORT
extern char *cplus_demangle(const char *, int); extern char *cplus_demangle(const char *, int);
......
...@@ -82,6 +82,20 @@ void thread__delete(struct thread *thread) ...@@ -82,6 +82,20 @@ void thread__delete(struct thread *thread)
free(thread); free(thread);
} }
struct thread *thread__get(struct thread *thread)
{
++thread->refcnt;
return thread;
}
void thread__put(struct thread *thread)
{
if (thread && --thread->refcnt == 0) {
list_del_init(&thread->node);
thread__delete(thread);
}
}
struct comm *thread__comm(const struct thread *thread) struct comm *thread__comm(const struct thread *thread)
{ {
if (list_empty(&thread->comm_list)) if (list_empty(&thread->comm_list))
......
...@@ -20,6 +20,7 @@ struct thread { ...@@ -20,6 +20,7 @@ struct thread {
pid_t tid; pid_t tid;
pid_t ppid; pid_t ppid;
int cpu; int cpu;
int refcnt;
char shortname[3]; char shortname[3];
bool comm_set; bool comm_set;
bool dead; /* if set thread has exited */ bool dead; /* if set thread has exited */
...@@ -37,6 +38,18 @@ struct comm; ...@@ -37,6 +38,18 @@ struct comm;
struct thread *thread__new(pid_t pid, pid_t tid); struct thread *thread__new(pid_t pid, pid_t tid);
int thread__init_map_groups(struct thread *thread, struct machine *machine); int thread__init_map_groups(struct thread *thread, struct machine *machine);
void thread__delete(struct thread *thread); void thread__delete(struct thread *thread);
struct thread *thread__get(struct thread *thread);
void thread__put(struct thread *thread);
static inline void __thread__zput(struct thread **thread)
{
thread__put(*thread);
*thread = NULL;
}
#define thread__zput(thread) __thread__zput(&thread)
static inline void thread__exited(struct thread *thread) static inline void thread__exited(struct thread *thread)
{ {
thread->dead = true; thread->dead = true;
......
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