From e4dc5b900a0735945428e8a2b7ab33b2630ff326 Mon Sep 17 00:00:00 2001 From: Kusanagi Kouichi Date: Wed, 18 Aug 2010 13:32:37 -0300 Subject: [PATCH] --- yaml --- r: 209664 b: refs/heads/master c: ecafda60e88031bcc4271c446f984ee883d69ea8 h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/arch/x86/kernel/cpu/perf_event_intel.c | 81 ++------ trunk/kernel/trace/ring_buffer.c | 3 - trunk/kernel/trace/trace.c | 11 +- trunk/kernel/trace/trace_events.c | 207 ++++++------------- trunk/kernel/trace/trace_functions_graph.c | 10 +- trunk/lib/Kconfig.debug | 5 +- trunk/scripts/recordmcount.pl | 7 +- trunk/tools/perf/Makefile | 14 +- trunk/tools/perf/feature-tests.mak | 2 +- 10 files changed, 100 insertions(+), 242 deletions(-) diff --git a/[refs] b/[refs] index 238454b1a98a..58f1476c2e37 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 351af0725e5222e35741011d1ea62215c1ed06db +refs/heads/master: ecafda60e88031bcc4271c446f984ee883d69ea8 diff --git a/trunk/arch/x86/kernel/cpu/perf_event_intel.c b/trunk/arch/x86/kernel/cpu/perf_event_intel.c index d8d86d014008..214ac860ebe0 100644 --- a/trunk/arch/x86/kernel/cpu/perf_event_intel.c +++ b/trunk/arch/x86/kernel/cpu/perf_event_intel.c @@ -491,78 +491,33 @@ static void intel_pmu_enable_all(int added) * Intel Errata AAP53 (model 30) * Intel Errata BD53 (model 44) * - * The official story: - * These chips need to be 'reset' when adding counters by programming the - * magic three (non-counting) events 0x4300B5, 0x4300D2, and 0x4300B1 either - * in sequence on the same PMC or on different PMCs. - * - * In practise it appears some of these events do in fact count, and - * we need to programm all 4 events. + * These chips need to be 'reset' when adding counters by programming + * the magic three (non counting) events 0x4300D2, 0x4300B1 and 0x4300B5 + * either in sequence on the same PMC or on different PMCs. */ -static void intel_pmu_nhm_workaround(void) +static void intel_pmu_nhm_enable_all(int added) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); - static const unsigned long nhm_magic[4] = { - 0x4300B5, - 0x4300D2, - 0x4300B1, - 0x4300B1 - }; - struct perf_event *event; - int i; - - /* - * The Errata requires below steps: - * 1) Clear MSR_IA32_PEBS_ENABLE and MSR_CORE_PERF_GLOBAL_CTRL; - * 2) Configure 4 PERFEVTSELx with the magic events and clear - * the corresponding PMCx; - * 3) set bit0~bit3 of MSR_CORE_PERF_GLOBAL_CTRL; - * 4) Clear MSR_CORE_PERF_GLOBAL_CTRL; - * 5) Clear 4 pairs of ERFEVTSELx and PMCx; - */ - - /* - * The real steps we choose are a little different from above. - * A) To reduce MSR operations, we don't run step 1) as they - * are already cleared before this function is called; - * B) Call x86_perf_event_update to save PMCx before configuring - * PERFEVTSELx with magic number; - * C) With step 5), we do clear only when the PERFEVTSELx is - * not used currently. - * D) Call x86_perf_event_set_period to restore PMCx; - */ + if (added) { + struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + int i; - /* We always operate 4 pairs of PERF Counters */ - for (i = 0; i < 4; i++) { - event = cpuc->events[i]; - if (event) - x86_perf_event_update(event); - } + wrmsrl(MSR_ARCH_PERFMON_EVENTSEL0 + 0, 0x4300D2); + wrmsrl(MSR_ARCH_PERFMON_EVENTSEL0 + 1, 0x4300B1); + wrmsrl(MSR_ARCH_PERFMON_EVENTSEL0 + 2, 0x4300B5); - for (i = 0; i < 4; i++) { - wrmsrl(MSR_ARCH_PERFMON_EVENTSEL0 + i, nhm_magic[i]); - wrmsrl(MSR_ARCH_PERFMON_PERFCTR0 + i, 0x0); - } + wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0x3); + wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0x0); - wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0xf); - wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0x0); + for (i = 0; i < 3; i++) { + struct perf_event *event = cpuc->events[i]; - for (i = 0; i < 4; i++) { - event = cpuc->events[i]; + if (!event) + continue; - if (event) { - x86_perf_event_set_period(event); __x86_pmu_enable_event(&event->hw, - ARCH_PERFMON_EVENTSEL_ENABLE); - } else - wrmsrl(MSR_ARCH_PERFMON_EVENTSEL0 + i, 0x0); + ARCH_PERFMON_EVENTSEL_ENABLE); + } } -} - -static void intel_pmu_nhm_enable_all(int added) -{ - if (added) - intel_pmu_nhm_workaround(); intel_pmu_enable_all(added); } diff --git a/trunk/kernel/trace/ring_buffer.c b/trunk/kernel/trace/ring_buffer.c index 19cccc3c3028..3632ce87674f 100644 --- a/trunk/kernel/trace/ring_buffer.c +++ b/trunk/kernel/trace/ring_buffer.c @@ -3846,9 +3846,6 @@ int ring_buffer_read_page(struct ring_buffer *buffer, rpos = reader->read; pos += size; - if (rpos >= commit) - break; - event = rb_reader_event(cpu_buffer); size = rb_event_length(event); } while (len > size); diff --git a/trunk/kernel/trace/trace.c b/trunk/kernel/trace/trace.c index 9ec59f541156..ba14a22be4cc 100644 --- a/trunk/kernel/trace/trace.c +++ b/trunk/kernel/trace/trace.c @@ -3463,7 +3463,6 @@ tracing_mark_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *fpos) { char *buf; - size_t written; if (tracing_disabled) return -EINVAL; @@ -3485,15 +3484,11 @@ tracing_mark_write(struct file *filp, const char __user *ubuf, } else buf[cnt] = '\0'; - written = mark_printk("%s", buf); + cnt = mark_printk("%s", buf); kfree(buf); - *fpos += written; - - /* don't tell userspace we wrote more - it might confuse them */ - if (written > cnt) - written = cnt; + *fpos += cnt; - return written; + return cnt; } static int tracing_clock_show(struct seq_file *m, void *v) diff --git a/trunk/kernel/trace/trace_events.c b/trunk/kernel/trace/trace_events.c index 4c758f146328..09b4fa6e4d3b 100644 --- a/trunk/kernel/trace/trace_events.c +++ b/trunk/kernel/trace/trace_events.c @@ -598,165 +598,88 @@ system_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, return ret; } -enum { - FORMAT_HEADER = 1, - FORMAT_PRINTFMT = 2, -}; - -static void *f_next(struct seq_file *m, void *v, loff_t *pos) +static void print_event_fields(struct trace_seq *s, struct list_head *head) { - struct ftrace_event_call *call = m->private; struct ftrace_event_field *field; - struct list_head *head; - - (*pos)++; - - switch ((unsigned long)v) { - case FORMAT_HEADER: - head = &ftrace_common_fields; - - if (unlikely(list_empty(head))) - return NULL; - - field = list_entry(head->prev, struct ftrace_event_field, link); - return field; - - case FORMAT_PRINTFMT: - /* all done */ - return NULL; - } - head = trace_get_fields(call); + list_for_each_entry_reverse(field, head, link) { + /* + * Smartly shows the array type(except dynamic array). + * Normal: + * field:TYPE VAR + * If TYPE := TYPE[LEN], it is shown: + * field:TYPE VAR[LEN] + */ + const char *array_descriptor = strchr(field->type, '['); - /* - * To separate common fields from event fields, the - * LSB is set on the first event field. Clear it in case. - */ - v = (void *)((unsigned long)v & ~1L); + if (!strncmp(field->type, "__data_loc", 10)) + array_descriptor = NULL; - field = v; - /* - * If this is a common field, and at the end of the list, then - * continue with main list. - */ - if (field->link.prev == &ftrace_common_fields) { - if (unlikely(list_empty(head))) - return NULL; - field = list_entry(head->prev, struct ftrace_event_field, link); - /* Set the LSB to notify f_show to print an extra newline */ - field = (struct ftrace_event_field *) - ((unsigned long)field | 1); - return field; + if (!array_descriptor) { + trace_seq_printf(s, "\tfield:%s %s;\toffset:%u;" + "\tsize:%u;\tsigned:%d;\n", + field->type, field->name, field->offset, + field->size, !!field->is_signed); + } else { + trace_seq_printf(s, "\tfield:%.*s %s%s;\toffset:%u;" + "\tsize:%u;\tsigned:%d;\n", + (int)(array_descriptor - field->type), + field->type, field->name, + array_descriptor, field->offset, + field->size, !!field->is_signed); + } } - - /* If we are done tell f_show to print the format */ - if (field->link.prev == head) - return (void *)FORMAT_PRINTFMT; - - field = list_entry(field->link.prev, struct ftrace_event_field, link); - - return field; -} - -static void *f_start(struct seq_file *m, loff_t *pos) -{ - loff_t l = 0; - void *p; - - /* Start by showing the header */ - if (!*pos) - return (void *)FORMAT_HEADER; - - p = (void *)FORMAT_HEADER; - do { - p = f_next(m, p, &l); - } while (p && l < *pos); - - return p; } -static int f_show(struct seq_file *m, void *v) +static ssize_t +event_format_read(struct file *filp, char __user *ubuf, size_t cnt, + loff_t *ppos) { - struct ftrace_event_call *call = m->private; - struct ftrace_event_field *field; - const char *array_descriptor; - - switch ((unsigned long)v) { - case FORMAT_HEADER: - seq_printf(m, "name: %s\n", call->name); - seq_printf(m, "ID: %d\n", call->event.type); - seq_printf(m, "format:\n"); - return 0; + struct ftrace_event_call *call = filp->private_data; + struct list_head *head; + struct trace_seq *s; + char *buf; + int r; - case FORMAT_PRINTFMT: - seq_printf(m, "\nprint fmt: %s\n", - call->print_fmt); + if (*ppos) return 0; - } - - /* - * To separate common fields from event fields, the - * LSB is set on the first event field. Clear it and - * print a newline if it is set. - */ - if ((unsigned long)v & 1) { - seq_putc(m, '\n'); - v = (void *)((unsigned long)v & ~1L); - } - - field = v; - - /* - * Smartly shows the array type(except dynamic array). - * Normal: - * field:TYPE VAR - * If TYPE := TYPE[LEN], it is shown: - * field:TYPE VAR[LEN] - */ - array_descriptor = strchr(field->type, '['); - if (!strncmp(field->type, "__data_loc", 10)) - array_descriptor = NULL; + s = kmalloc(sizeof(*s), GFP_KERNEL); + if (!s) + return -ENOMEM; - if (!array_descriptor) - seq_printf(m, "\tfield:%s %s;\toffset:%u;\tsize:%u;\tsigned:%d;\n", - field->type, field->name, field->offset, - field->size, !!field->is_signed); - else - seq_printf(m, "\tfield:%.*s %s%s;\toffset:%u;\tsize:%u;\tsigned:%d;\n", - (int)(array_descriptor - field->type), - field->type, field->name, - array_descriptor, field->offset, - field->size, !!field->is_signed); + trace_seq_init(s); - return 0; -} + trace_seq_printf(s, "name: %s\n", call->name); + trace_seq_printf(s, "ID: %d\n", call->event.type); + trace_seq_printf(s, "format:\n"); -static void f_stop(struct seq_file *m, void *p) -{ -} + /* print common fields */ + print_event_fields(s, &ftrace_common_fields); -static const struct seq_operations trace_format_seq_ops = { - .start = f_start, - .next = f_next, - .stop = f_stop, - .show = f_show, -}; + trace_seq_putc(s, '\n'); -static int trace_format_open(struct inode *inode, struct file *file) -{ - struct ftrace_event_call *call = inode->i_private; - struct seq_file *m; - int ret; + /* print event specific fields */ + head = trace_get_fields(call); + print_event_fields(s, head); - ret = seq_open(file, &trace_format_seq_ops); - if (ret < 0) - return ret; + r = trace_seq_printf(s, "\nprint fmt: %s\n", call->print_fmt); - m = file->private_data; - m->private = call; + if (!r) { + /* + * ug! The format output is bigger than a PAGE!! + */ + buf = "FORMAT TOO BIG\n"; + r = simple_read_from_buffer(ubuf, cnt, ppos, + buf, strlen(buf)); + goto out; + } - return 0; + r = simple_read_from_buffer(ubuf, cnt, ppos, + s->buffer, s->len); + out: + kfree(s); + return r; } static ssize_t @@ -954,10 +877,8 @@ static const struct file_operations ftrace_enable_fops = { }; static const struct file_operations ftrace_event_format_fops = { - .open = trace_format_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, + .open = tracing_open_generic, + .read = event_format_read, }; static const struct file_operations ftrace_event_id_fops = { diff --git a/trunk/kernel/trace/trace_functions_graph.c b/trunk/kernel/trace/trace_functions_graph.c index 6f233698518e..6bff23625781 100644 --- a/trunk/kernel/trace/trace_functions_graph.c +++ b/trunk/kernel/trace/trace_functions_graph.c @@ -507,15 +507,7 @@ get_return_for_leaf(struct trace_iterator *iter, * if the output fails. */ data->ent = *curr; - /* - * If the next event is not a return type, then - * we only care about what type it is. Otherwise we can - * safely copy the entire event. - */ - if (next->ent.type == TRACE_GRAPH_RET) - data->ret = *next; - else - data->ret.ent.type = next->ent.type; + data->ret = *next; } } diff --git a/trunk/lib/Kconfig.debug b/trunk/lib/Kconfig.debug index 1b4afd2e6ca0..9e06b7f5ecf1 100644 --- a/trunk/lib/Kconfig.debug +++ b/trunk/lib/Kconfig.debug @@ -994,16 +994,13 @@ config FAULT_INJECTION_STACKTRACE_FILTER config LATENCYTOP bool "Latency measuring infrastructure" - depends on HAVE_LATENCYTOP_SUPPORT - depends on DEBUG_KERNEL - depends on STACKTRACE_SUPPORT - depends on PROC_FS select FRAME_POINTER if !MIPS && !PPC && !S390 && !MICROBLAZE select KALLSYMS select KALLSYMS_ALL select STACKTRACE select SCHEDSTATS select SCHED_DEBUG + depends on HAVE_LATENCYTOP_SUPPORT help Enable this option if you want to use the LatencyTOP tool to find out which userspace is blocking on what kernel operations. diff --git a/trunk/scripts/recordmcount.pl b/trunk/scripts/recordmcount.pl index e67f05486087..0171060b5fd6 100755 --- a/trunk/scripts/recordmcount.pl +++ b/trunk/scripts/recordmcount.pl @@ -159,7 +159,6 @@ my $function_regex; # Find the name of a function # (return offset and func name) my $mcount_regex; # Find the call site to mcount (return offset) -my $mcount_adjust; # Address adjustment to mcount offset my $alignment; # The .align value to use for $mcount_section my $section_type; # Section header plus possible alignment command my $can_use_local = 0; # If we can use local function references @@ -214,7 +213,6 @@ sub check_objcopy $function_regex = "^([0-9a-fA-F]+)\\s+<(.*?)>:"; $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\smcount\$"; $section_type = '@progbits'; -$mcount_adjust = 0; $type = ".long"; if ($arch eq "x86_64") { @@ -353,9 +351,6 @@ sub check_objcopy } elsif ($arch eq "microblaze") { # Microblaze calls '_mcount' instead of plain 'mcount'. $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$"; -} elsif ($arch eq "blackfin") { - $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s__mcount\$"; - $mcount_adjust = -4; } else { die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD"; } @@ -516,7 +511,7 @@ sub update_funcs } # is this a call site to mcount? If so, record it to print later if ($text_found && /$mcount_regex/) { - push(@offsets, (hex $1) + $mcount_adjust); + push(@offsets, hex $1); } } diff --git a/trunk/tools/perf/Makefile b/trunk/tools/perf/Makefile index dcb9700b88d2..4f1fa77c1feb 100644 --- a/trunk/tools/perf/Makefile +++ b/trunk/tools/perf/Makefile @@ -5,6 +5,12 @@ endif # The default target of this Makefile is... all:: +ifneq ($(OUTPUT),) +# check that the output directory actually exists +OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd) +$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist)) +endif + # Define V=1 to have a more verbose compile. # Define V=2 to have an even more verbose compile. # @@ -931,15 +937,15 @@ $(OUTPUT)common-cmds.h: $(wildcard Documentation/perf-*.txt) $(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@ $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh - $(QUIET_GEN)$(RM) $@ $@+ && \ + $(QUIET_GEN)$(RM) $(OUTPUT)$@ $(OUTPUT)$@+ && \ sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \ -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \ -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \ -e 's/@@NO_CURL@@/$(NO_CURL)/g' \ - $@.sh >$@+ && \ - chmod +x $@+ && \ - mv $@+ $(OUTPUT)$@ + $@.sh > $(OUTPUT)$@+ && \ + chmod +x $(OUTPUT)$@+ && \ + mv $(OUTPUT)$@+ $(OUTPUT)$@ configure: configure.ac $(QUIET_GEN)$(RM) $@ $<+ && \ diff --git a/trunk/tools/perf/feature-tests.mak b/trunk/tools/perf/feature-tests.mak index ddb68e601f0e..7a7b60859053 100644 --- a/trunk/tools/perf/feature-tests.mak +++ b/trunk/tools/perf/feature-tests.mak @@ -113,7 +113,7 @@ endef # try-cc # Usage: option = $(call try-cc, source-to-build, cc-options) try-cc = $(shell sh -c \ - 'TMP="$(TMPOUT).$$$$"; \ + 'TMP="$(OUTPUT)$(TMPOUT).$$$$"; \ echo "$(1)" | \ $(CC) -x c - $(2) -o "$$TMP" > /dev/null 2>&1 && echo y; \ rm -f "$$TMP"')