Skip to content

Commit

Permalink
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux…
Browse files Browse the repository at this point in the history
…/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>
  • Loading branch information
Ingo Molnar committed Mar 3, 2015
2 parents 788b94b + ae536ac commit 94ac003
Show file tree
Hide file tree
Showing 31 changed files with 231 additions and 132 deletions.
54 changes: 40 additions & 14 deletions arch/x86/kernel/kprobes/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -223,34 +223,56 @@ static unsigned long
__recover_probed_insn(kprobe_opcode_t *buf, unsigned long addr)
{
struct kprobe *kp;
unsigned long faddr;

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;

/*
* 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;
}

/*
* Recover the probed instruction at addr for further analysis.
* Caller must lock kprobes by kprobe_mutex, or disable preemption
* 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)
{
Expand Down Expand Up @@ -285,6 +307,8 @@ static int can_probe(unsigned long paddr)
* normally used, we just go through if there is no kprobe.
*/
__addr = recover_probed_instruction(buf, addr);
if (!__addr)
return 0;
kernel_insn_init(&insn, (void *)__addr, MAX_INSN_SIZE);
insn_get_length(&insn);

Expand Down Expand Up @@ -333,6 +357,8 @@ int __copy_instruction(u8 *dest, u8 *src)
unsigned long recovered_insn =
recover_probed_instruction(buf, (unsigned long)src);

if (!recovered_insn)
return 0;
kernel_insn_init(&insn, (void *)recovered_insn, MAX_INSN_SIZE);
insn_get_length(&insn);
/* Another subsystem puts a breakpoint, failed to recover */
Expand Down
2 changes: 2 additions & 0 deletions arch/x86/kernel/kprobes/opt.c
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,8 @@ static int can_optimize(unsigned long paddr)
*/
return 0;
recovered_insn = recover_probed_instruction(buf, addr);
if (!recovered_insn)
return 0;
kernel_insn_init(&insn, (void *)recovered_insn, MAX_INSN_SIZE);
insn_get_length(&insn);
/* Another subsystem puts a breakpoint */
Expand Down
2 changes: 1 addition & 1 deletion kernel/events/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
* 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;

if (vma_size != PAGE_SIZE * (1 + nr_pages))
Expand Down
1 change: 1 addition & 0 deletions tools/perf/.gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
PERF-CFLAGS
PERF-GUI-VARS
PERF-VERSION-FILE
PERF-FEATURES
perf
perf-read-vdso32
perf-read-vdsox32
Expand Down
12 changes: 9 additions & 3 deletions tools/perf/Documentation/perf-record.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,18 @@ OPTIONS
If you want to profile write accesses in [0x1000~1008), just set
'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>::
Event filter.

-a::
--all-cpus::
System-wide collection from all CPUs.

-l::
Scale counter values.

-p::
--pid=::
Record events on existing process ID (comma separated list).
Expand Down Expand Up @@ -107,6 +109,10 @@ OPTIONS
specification with appended unit character - B/K/M/G. The
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::
Enables call-graph (stack chain/backtrace) recording.

Expand Down
2 changes: 1 addition & 1 deletion tools/perf/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ unexport MAKEFLAGS
#
ifeq ($(JOBS),)
JOBS := $(shell grep -c ^processor /proc/cpuinfo 2>/dev/null)
ifeq ($(JOBS),)
ifeq ($(JOBS),0)
JOBS := 1
endif
endif
Expand Down
4 changes: 2 additions & 2 deletions tools/perf/bench/mem-memcpy.c
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ static u64 do_memcpy_cycle(const struct routine *r, size_t len, bool prefault)
memcpy_t fn = r->fn.memcpy;
int i;

memcpy_alloc_mem(&src, &dst, len);
memcpy_alloc_mem(&dst, &src, len);

if (prefault)
fn(dst, src, len);
Expand All @@ -312,7 +312,7 @@ static double do_memcpy_gettimeofday(const struct routine *r, size_t len,
void *src = NULL, *dst = NULL;
int i;

memcpy_alloc_mem(&src, &dst, len);
memcpy_alloc_mem(&dst, &src, len);

if (prefault)
fn(dst, src, len);
Expand Down
26 changes: 9 additions & 17 deletions tools/perf/builtin-sched.c
Original file line number Diff line number Diff line change
Expand Up @@ -831,7 +831,7 @@ static int thread_atoms_insert(struct perf_sched *sched, struct thread *thread)
return -1;
}

atoms->thread = thread;
atoms->thread = thread__get(thread);
INIT_LIST_HEAD(&atoms->work_list);
__thread_latency_insert(&sched->atom_root, atoms, &sched->cmp_pid);
return 0;
Expand Down Expand Up @@ -1439,8 +1439,7 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_
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[] = {
{ "sched:sched_switch", process_sched_switch_event, },
Expand All @@ -1454,6 +1453,7 @@ static int perf_sched__read_events(struct perf_sched *sched,
.path = input_name,
.mode = PERF_DATA_MODE_READ,
};
int rc = -1;

session = perf_session__new(&file, false, &sched->tool);
if (session == NULL) {
Expand All @@ -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];
}

if (psession)
*psession = session;
else
perf_session__delete(session);

return 0;

rc = 0;
out_delete:
perf_session__delete(session);
return -1;
return rc;
}

static void print_bad_events(struct perf_sched *sched)
Expand Down Expand Up @@ -1515,12 +1509,10 @@ static void print_bad_events(struct perf_sched *sched)
static int perf_sched__lat(struct perf_sched *sched)
{
struct rb_node *next;
struct perf_session *session;

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;

perf_sched__sort_lat(sched);
Expand All @@ -1537,6 +1529,7 @@ static int perf_sched__lat(struct perf_sched *sched)
work_list = rb_entry(next, struct work_atoms, node);
output_lat_thread(sched, work_list);
next = rb_next(next);
thread__zput(work_list->thread);
}

printf(" -----------------------------------------------------------------------------------------------------------------\n");
Expand All @@ -1548,7 +1541,6 @@ static int perf_sched__lat(struct perf_sched *sched)
print_bad_events(sched);
printf("\n");

perf_session__delete(session);
return 0;
}

Expand All @@ -1557,7 +1549,7 @@ static int perf_sched__map(struct perf_sched *sched)
sched->max_cpu = sysconf(_SC_NPROCESSORS_CONF);

setup_pager();
if (perf_sched__read_events(sched, NULL))
if (perf_sched__read_events(sched))
return -1;
print_bad_events(sched);
return 0;
Expand All @@ -1572,7 +1564,7 @@ static int perf_sched__replay(struct perf_sched *sched)

test_calibrations(sched);

if (perf_sched__read_events(sched, NULL))
if (perf_sched__read_events(sched))
return -1;

printf("nr_run_events: %ld\n", sched->nr_run_events);
Expand Down
5 changes: 4 additions & 1 deletion tools/perf/builtin-stat.c
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,9 @@ static int read_counter(struct perf_evsel *counter)
int ncpus = perf_evsel__nr_cpus(counter);
int cpu, thread;

if (!counter->supported)
return -ENOENT;

if (counter->system_wide)
nthreads = 1;

Expand Down Expand Up @@ -1285,7 +1288,7 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
if (prefix)
fprintf(output, "%s", prefix);

if (scaled == -1) {
if (scaled == -1 || !counter->supported) {
fprintf(output, "%*s%s",
csv_output ? 0 : 18,
counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
Expand Down
7 changes: 6 additions & 1 deletion tools/perf/builtin-trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -1741,7 +1741,10 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
} else
ttrace->entry_pending = true;

trace->current = thread;
if (trace->current != thread) {
thread__put(trace->current);
trace->current = thread__get(thread);
}

return 0;
}
Expand Down Expand Up @@ -2274,6 +2277,8 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
}

out_disable:
thread__zput(trace->current);

perf_evlist__disable(evlist);

if (!err) {
Expand Down
17 changes: 8 additions & 9 deletions tools/perf/config/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,7 @@ else
ifneq ($(feature-libperl), 1)
CFLAGS += -DNO_LIBPERL
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
LDFLAGS += $(PERL_EMBED_LDFLAGS)
EXTLIBS += $(PERL_EMBED_LIBADD)
Expand All @@ -548,22 +548,21 @@ endif
disable-python = $(eval $(disable-python_code))
define disable-python_code
CFLAGS += -DNO_LIBPYTHON
$(if $(1),$(warning No $(1) was found))
$(warning Python support will not be built)
$(warning $1)
NO_LIBPYTHON := 1
endef

ifdef NO_LIBPYTHON
$(call disable-python)
$(call disable-python,Python support disabled by user)
else

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
PYTHON_WORD := $(call shell-wordify,$(PYTHON))

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

PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG))
Expand All @@ -575,7 +574,7 @@ else
FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)

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

ifneq ($(feature-libpython-version), 1)
Expand Down Expand Up @@ -636,7 +635,7 @@ else
EXTLIBS += -liberty
CFLAGS += -DHAVE_CPLUS_DEMANGLE_SUPPORT
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
endif
endif
Expand Down Expand Up @@ -707,7 +706,7 @@ endif

ifndef NO_LIBBABELTRACE
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
else
CFLAGS += -DHAVE_LIBBABELTRACE_SUPPORT $(LIBBABELTRACE_CFLAGS)
Expand Down
Loading

0 comments on commit 94ac003

Please sign in to comment.