Browse Source

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: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Ingo Molnar 10 years ago
parent
commit
94ac003b66

+ 40 - 14
arch/x86/kernel/kprobes/core.c

@@ -223,27 +223,48 @@ 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 */
-	if (!kp)
+	faddr = ftrace_location(addr);
+	/*
+	 * 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;
 
 
 	/*
 	/*
-	 *  Basically, kp->ainsn.insn has an original instruction.
-	 *  However, RIP-relative instruction can not do single-stepping
-	 *  at different place, __copy_instruction() tweaks the displacement of
-	 *  that instruction. In that case, we can't recover the instruction
-	 *  from the kp->ainsn.insn.
+	 * Basically, kp->ainsn.insn has an original instruction.
+	 * However, RIP-relative instruction can not do single-stepping
+	 * at different place, __copy_instruction() tweaks the displacement of
+	 * that instruction. In that case, we can't recover the instruction
+	 * from the kp->ainsn.insn.
 	 *
 	 *
-	 *  On the other hand, kp->opcode has a copy of the first byte of
-	 *  the probed instruction, which is overwritten by int3. And
-	 *  the instruction at kp->addr is not modified by kprobes except
-	 *  for the first byte, we can recover the original instruction
-	 *  from it and kp->opcode.
+	 * On the other hand, in case on normal Kprobe, kp->opcode has a copy
+	 * of the first byte of the probed instruction, which is overwritten
+	 * by int3. And the instruction at kp->addr is not modified by kprobes
+	 * except for the first byte, we can recover the original instruction
+	 * 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));
-	buf[0] = kp->opcode;
+	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;
 	return (unsigned long)buf;
 	return (unsigned long)buf;
 }
 }
 
 
@@ -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)
 		 * 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)
 	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 */

+ 2 - 0
arch/x86/kernel/kprobes/opt.c

@@ -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 */

+ 1 - 1
kernel/events/core.c

@@ -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))

+ 1 - 0
tools/perf/.gitignore

@@ -1,6 +1,7 @@
 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

+ 9 - 3
tools/perf/Documentation/perf-record.txt

@@ -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
 --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
 	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.
 
 

+ 1 - 1
tools/perf/Makefile

@@ -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

+ 2 - 2
tools/perf/bench/mem-memcpy.c

@@ -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,
 	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);

+ 9 - 17
tools/perf/builtin-sched.c

@@ -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_
 	return err;
 	return err;
 }
 }
 
 
-static int perf_sched__read_events(struct perf_sched *sched,
-				   struct perf_session **psession)
+static int perf_sched__read_events(struct perf_sched *sched)
 {
 {
 	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,
 		.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,
 		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)
-		*psession = session;
-	else
-		perf_session__delete(session);
-
-	return 0;
-
+	rc = 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)
 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, &session))
+	if (perf_sched__read_events(sched))
 		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)
 		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)
 	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)
 	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)
 
 
 	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);

+ 4 - 1
tools/perf/builtin-stat.c

@@ -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)
 	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,

+ 6 - 1
tools/perf/builtin-trace.c

@@ -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 @@ next_event:
 	}
 	}
 
 
 out_disable:
 out_disable:
+	thread__zput(trace->current);
+
 	perf_evlist__disable(evlist);
 	perf_evlist__disable(evlist);
 
 
 	if (!err) {
 	if (!err) {

+ 8 - 9
tools/perf/config/Makefile

@@ -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
 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 Python support will not be built)
+  $(warning $1)
   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
       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
             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
 
 
 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)

+ 5 - 18
tools/perf/config/Makefile.arch

@@ -1,28 +1,15 @@
+ifndef ARCH
+ARCH := $(shell uname -m 2>/dev/null || echo not)
+endif
 
 
-uname_M := $(shell uname -m 2>/dev/null || echo not)
-
-RAW_ARCH := $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
+ARCH := $(shell echo $(ARCH) | sed -e s/i.86/x86/ -e s/x86_64/x86/ \
+                                  -e s/sun4u/sparc/ -e s/sparc64/sparc/ \
                                   -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

+ 8 - 8
tools/perf/config/feature-checks/Makefile

@@ -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:
 	$(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:
 	$(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

+ 5 - 2
tools/perf/config/feature-checks/test-pthread-attr-setaffinity-np.c

@@ -1,14 +1,17 @@
 #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 */
-	ret = pthread_attr_setaffinity_np(&thread_attr, 0, NULL);
+	CPU_ZERO(&cs);
+
+	ret = pthread_attr_setaffinity_np(&thread_attr, sizeof(cs), &cs);
 
 
 	return ret;
 	return ret;
 }
 }

+ 1 - 2
tools/perf/config/utilities.mak

@@ -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)))
-_gea_warn = $(warning The path '$(1)' is not executable.)
+_ge_attempt = $(if $(get-executable),$(get-executable),$(call _gea_err,$(2)))
 _gea_err  = $(if $(1),$(error Please set '$(1)' appropriately))
 _gea_err  = $(if $(1),$(error Please set '$(1)' appropriately))

+ 3 - 3
tools/perf/ui/browsers/hists.c

@@ -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 @@ zoom_thread:
 				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);
 			}
 			}

+ 1 - 1
tools/perf/util/Build

@@ -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
 
 

+ 3 - 2
tools/perf/util/build-id.c

@@ -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;
-		thread__delete(thread);
+		if (machine->last_match == thread)
+			thread__zput(machine->last_match);
+		thread__put(thread);
 	}
 	}
 
 
 	return 0;
 	return 0;

+ 15 - 3
tools/perf/util/cloexec.c

@@ -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)
 		  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 */
-	fd = sys_perf_event_open(&attr, pid, cpu, -1, 0);
+	while (1) {
+		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;
 }
 }
 
 

+ 24 - 10
tools/perf/util/event.c

@@ -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,
-					 union perf_event *event, pid_t pid,
-					 perf_event__handler_t process,
+static pid_t perf_event__prepare_comm(union perf_event *event, pid_t pid,
 					 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,
 				(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,
 {
 {
 	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,
 		if (*end)
 		if (*end)
 			continue;
 			continue;
 
 
-		tgid = perf_event__synthesize_comm(tool, comm_event, _pid,
-						   process, machine);
+		tgid = perf_event__prepare_comm(comm_event, _pid, 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)

+ 1 - 1
tools/perf/util/evlist.h

@@ -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 {

+ 2 - 0
tools/perf/util/hist.c

@@ -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)
 
 
 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);

+ 1 - 1
tools/perf/util/hist.h

@@ -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;

+ 23 - 21
tools/perf/util/machine.c

@@ -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)
 	}
 	}
 }
 }
 
 
-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)
 	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,9 +352,13 @@ 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) {
-		machine__update_thread_pid(machine, th, pid);
-		return th;
+	if (th != NULL) {
+		if (th->tid == tid) {
+			machine__update_thread_pid(machine, th, pid);
+			return th;
+		}
+
+		thread__zput(machine->last_match);
 	}
 	}
 
 
 	while (*p != NULL) {
 	while (*p != NULL) {
@@ -371,7 +366,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
 		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,
 			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 @@ out_problem:
 
 
 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
-	 * instances, so just move them to a separate list.
+	 * Move it first to the dead_threads list, then drop the reference,
+	 * 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,

+ 0 - 1
tools/perf/util/machine.h

@@ -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);
 
 

+ 23 - 0
tools/perf/util/probe-event.c

@@ -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,
 		 */
 		 */
 		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) {

+ 1 - 4
tools/perf/util/probe-finder.c

@@ -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;

+ 0 - 6
tools/perf/util/session.c

@@ -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)
 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);

+ 5 - 0
tools/perf/util/symbol-elf.c

@@ -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);
 
 

+ 14 - 0
tools/perf/util/thread.c

@@ -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))

+ 13 - 0
tools/perf/util/thread.h

@@ -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;
 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;