diff options
author | Steven Rostedt <srostedt@redhat.com> | 2010-08-16 11:17:30 -0400 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2010-08-16 11:17:30 -0400 |
commit | d244b6bd41e09ecbb09c738cc2c108be227398c8 (patch) | |
tree | 848c6a8a0d6f83929daf43d63e241dc8072066ac | |
parent | da5cabf80e2433131bf0ed8993abc0f7ea618c73 (diff) | |
parent | 1aa54bca6ee0d07ebcafb8ca8074b624d80724aa (diff) |
Merge branch 'tip/perf/urgent-3' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-2.6-trace into trace/tip/perf/urgent-4
Conflicts:
kernel/trace/trace_events.c
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r-- | kernel/trace/ring_buffer.c | 3 | ||||
-rw-r--r-- | kernel/trace/trace.c | 11 | ||||
-rw-r--r-- | kernel/trace/trace_events.c | 207 | ||||
-rw-r--r-- | kernel/trace/trace_functions_graph.c | 10 | ||||
-rwxr-xr-x | scripts/recordmcount.pl | 7 |
5 files changed, 169 insertions, 69 deletions
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 3632ce87674f..19cccc3c3028 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c | |||
@@ -3846,6 +3846,9 @@ int ring_buffer_read_page(struct ring_buffer *buffer, | |||
3846 | rpos = reader->read; | 3846 | rpos = reader->read; |
3847 | pos += size; | 3847 | pos += size; |
3848 | 3848 | ||
3849 | if (rpos >= commit) | ||
3850 | break; | ||
3851 | |||
3849 | event = rb_reader_event(cpu_buffer); | 3852 | event = rb_reader_event(cpu_buffer); |
3850 | size = rb_event_length(event); | 3853 | size = rb_event_length(event); |
3851 | } while (len > size); | 3854 | } while (len > size); |
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index ba14a22be4cc..9ec59f541156 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -3463,6 +3463,7 @@ tracing_mark_write(struct file *filp, const char __user *ubuf, | |||
3463 | size_t cnt, loff_t *fpos) | 3463 | size_t cnt, loff_t *fpos) |
3464 | { | 3464 | { |
3465 | char *buf; | 3465 | char *buf; |
3466 | size_t written; | ||
3466 | 3467 | ||
3467 | if (tracing_disabled) | 3468 | if (tracing_disabled) |
3468 | return -EINVAL; | 3469 | return -EINVAL; |
@@ -3484,11 +3485,15 @@ tracing_mark_write(struct file *filp, const char __user *ubuf, | |||
3484 | } else | 3485 | } else |
3485 | buf[cnt] = '\0'; | 3486 | buf[cnt] = '\0'; |
3486 | 3487 | ||
3487 | cnt = mark_printk("%s", buf); | 3488 | written = mark_printk("%s", buf); |
3488 | kfree(buf); | 3489 | kfree(buf); |
3489 | *fpos += cnt; | 3490 | *fpos += written; |
3490 | 3491 | ||
3491 | return cnt; | 3492 | /* don't tell userspace we wrote more - it might confuse them */ |
3493 | if (written > cnt) | ||
3494 | written = cnt; | ||
3495 | |||
3496 | return written; | ||
3492 | } | 3497 | } |
3493 | 3498 | ||
3494 | static int tracing_clock_show(struct seq_file *m, void *v) | 3499 | static int tracing_clock_show(struct seq_file *m, void *v) |
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 09b4fa6e4d3b..4c758f146328 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
@@ -598,88 +598,165 @@ out: | |||
598 | return ret; | 598 | return ret; |
599 | } | 599 | } |
600 | 600 | ||
601 | static void print_event_fields(struct trace_seq *s, struct list_head *head) | 601 | enum { |
602 | FORMAT_HEADER = 1, | ||
603 | FORMAT_PRINTFMT = 2, | ||
604 | }; | ||
605 | |||
606 | static void *f_next(struct seq_file *m, void *v, loff_t *pos) | ||
602 | { | 607 | { |
608 | struct ftrace_event_call *call = m->private; | ||
603 | struct ftrace_event_field *field; | 609 | struct ftrace_event_field *field; |
610 | struct list_head *head; | ||
604 | 611 | ||
605 | list_for_each_entry_reverse(field, head, link) { | 612 | (*pos)++; |
606 | /* | ||
607 | * Smartly shows the array type(except dynamic array). | ||
608 | * Normal: | ||
609 | * field:TYPE VAR | ||
610 | * If TYPE := TYPE[LEN], it is shown: | ||
611 | * field:TYPE VAR[LEN] | ||
612 | */ | ||
613 | const char *array_descriptor = strchr(field->type, '['); | ||
614 | 613 | ||
615 | if (!strncmp(field->type, "__data_loc", 10)) | 614 | switch ((unsigned long)v) { |
616 | array_descriptor = NULL; | 615 | case FORMAT_HEADER: |
616 | head = &ftrace_common_fields; | ||
617 | 617 | ||
618 | if (!array_descriptor) { | 618 | if (unlikely(list_empty(head))) |
619 | trace_seq_printf(s, "\tfield:%s %s;\toffset:%u;" | 619 | return NULL; |
620 | "\tsize:%u;\tsigned:%d;\n", | 620 | |
621 | field->type, field->name, field->offset, | 621 | field = list_entry(head->prev, struct ftrace_event_field, link); |
622 | field->size, !!field->is_signed); | 622 | return field; |
623 | } else { | 623 | |
624 | trace_seq_printf(s, "\tfield:%.*s %s%s;\toffset:%u;" | 624 | case FORMAT_PRINTFMT: |
625 | "\tsize:%u;\tsigned:%d;\n", | 625 | /* all done */ |
626 | (int)(array_descriptor - field->type), | 626 | return NULL; |
627 | field->type, field->name, | 627 | } |
628 | array_descriptor, field->offset, | 628 | |
629 | field->size, !!field->is_signed); | 629 | head = trace_get_fields(call); |
630 | } | 630 | |
631 | /* | ||
632 | * To separate common fields from event fields, the | ||
633 | * LSB is set on the first event field. Clear it in case. | ||
634 | */ | ||
635 | v = (void *)((unsigned long)v & ~1L); | ||
636 | |||
637 | field = v; | ||
638 | /* | ||
639 | * If this is a common field, and at the end of the list, then | ||
640 | * continue with main list. | ||
641 | */ | ||
642 | if (field->link.prev == &ftrace_common_fields) { | ||
643 | if (unlikely(list_empty(head))) | ||
644 | return NULL; | ||
645 | field = list_entry(head->prev, struct ftrace_event_field, link); | ||
646 | /* Set the LSB to notify f_show to print an extra newline */ | ||
647 | field = (struct ftrace_event_field *) | ||
648 | ((unsigned long)field | 1); | ||
649 | return field; | ||
631 | } | 650 | } |
651 | |||
652 | /* If we are done tell f_show to print the format */ | ||
653 | if (field->link.prev == head) | ||
654 | return (void *)FORMAT_PRINTFMT; | ||
655 | |||
656 | field = list_entry(field->link.prev, struct ftrace_event_field, link); | ||
657 | |||
658 | return field; | ||
632 | } | 659 | } |
633 | 660 | ||
634 | static ssize_t | 661 | static void *f_start(struct seq_file *m, loff_t *pos) |
635 | event_format_read(struct file *filp, char __user *ubuf, size_t cnt, | ||
636 | loff_t *ppos) | ||
637 | { | 662 | { |
638 | struct ftrace_event_call *call = filp->private_data; | 663 | loff_t l = 0; |
639 | struct list_head *head; | 664 | void *p; |
640 | struct trace_seq *s; | ||
641 | char *buf; | ||
642 | int r; | ||
643 | 665 | ||
644 | if (*ppos) | 666 | /* Start by showing the header */ |
667 | if (!*pos) | ||
668 | return (void *)FORMAT_HEADER; | ||
669 | |||
670 | p = (void *)FORMAT_HEADER; | ||
671 | do { | ||
672 | p = f_next(m, p, &l); | ||
673 | } while (p && l < *pos); | ||
674 | |||
675 | return p; | ||
676 | } | ||
677 | |||
678 | static int f_show(struct seq_file *m, void *v) | ||
679 | { | ||
680 | struct ftrace_event_call *call = m->private; | ||
681 | struct ftrace_event_field *field; | ||
682 | const char *array_descriptor; | ||
683 | |||
684 | switch ((unsigned long)v) { | ||
685 | case FORMAT_HEADER: | ||
686 | seq_printf(m, "name: %s\n", call->name); | ||
687 | seq_printf(m, "ID: %d\n", call->event.type); | ||
688 | seq_printf(m, "format:\n"); | ||
645 | return 0; | 689 | return 0; |
646 | 690 | ||
647 | s = kmalloc(sizeof(*s), GFP_KERNEL); | 691 | case FORMAT_PRINTFMT: |
648 | if (!s) | 692 | seq_printf(m, "\nprint fmt: %s\n", |
649 | return -ENOMEM; | 693 | call->print_fmt); |
694 | return 0; | ||
695 | } | ||
650 | 696 | ||
651 | trace_seq_init(s); | 697 | /* |
698 | * To separate common fields from event fields, the | ||
699 | * LSB is set on the first event field. Clear it and | ||
700 | * print a newline if it is set. | ||
701 | */ | ||
702 | if ((unsigned long)v & 1) { | ||
703 | seq_putc(m, '\n'); | ||
704 | v = (void *)((unsigned long)v & ~1L); | ||
705 | } | ||
652 | 706 | ||
653 | trace_seq_printf(s, "name: %s\n", call->name); | 707 | field = v; |
654 | trace_seq_printf(s, "ID: %d\n", call->event.type); | ||
655 | trace_seq_printf(s, "format:\n"); | ||
656 | 708 | ||
657 | /* print common fields */ | 709 | /* |
658 | print_event_fields(s, &ftrace_common_fields); | 710 | * Smartly shows the array type(except dynamic array). |
711 | * Normal: | ||
712 | * field:TYPE VAR | ||
713 | * If TYPE := TYPE[LEN], it is shown: | ||
714 | * field:TYPE VAR[LEN] | ||
715 | */ | ||
716 | array_descriptor = strchr(field->type, '['); | ||
659 | 717 | ||
660 | trace_seq_putc(s, '\n'); | 718 | if (!strncmp(field->type, "__data_loc", 10)) |
719 | array_descriptor = NULL; | ||
661 | 720 | ||
662 | /* print event specific fields */ | 721 | if (!array_descriptor) |
663 | head = trace_get_fields(call); | 722 | seq_printf(m, "\tfield:%s %s;\toffset:%u;\tsize:%u;\tsigned:%d;\n", |
664 | print_event_fields(s, head); | 723 | field->type, field->name, field->offset, |
724 | field->size, !!field->is_signed); | ||
725 | else | ||
726 | seq_printf(m, "\tfield:%.*s %s%s;\toffset:%u;\tsize:%u;\tsigned:%d;\n", | ||
727 | (int)(array_descriptor - field->type), | ||
728 | field->type, field->name, | ||
729 | array_descriptor, field->offset, | ||
730 | field->size, !!field->is_signed); | ||
665 | 731 | ||
666 | r = trace_seq_printf(s, "\nprint fmt: %s\n", call->print_fmt); | 732 | return 0; |
733 | } | ||
667 | 734 | ||
668 | if (!r) { | 735 | static void f_stop(struct seq_file *m, void *p) |
669 | /* | 736 | { |
670 | * ug! The format output is bigger than a PAGE!! | 737 | } |
671 | */ | ||
672 | buf = "FORMAT TOO BIG\n"; | ||
673 | r = simple_read_from_buffer(ubuf, cnt, ppos, | ||
674 | buf, strlen(buf)); | ||
675 | goto out; | ||
676 | } | ||
677 | 738 | ||
678 | r = simple_read_from_buffer(ubuf, cnt, ppos, | 739 | static const struct seq_operations trace_format_seq_ops = { |
679 | s->buffer, s->len); | 740 | .start = f_start, |
680 | out: | 741 | .next = f_next, |
681 | kfree(s); | 742 | .stop = f_stop, |
682 | return r; | 743 | .show = f_show, |
744 | }; | ||
745 | |||
746 | static int trace_format_open(struct inode *inode, struct file *file) | ||
747 | { | ||
748 | struct ftrace_event_call *call = inode->i_private; | ||
749 | struct seq_file *m; | ||
750 | int ret; | ||
751 | |||
752 | ret = seq_open(file, &trace_format_seq_ops); | ||
753 | if (ret < 0) | ||
754 | return ret; | ||
755 | |||
756 | m = file->private_data; | ||
757 | m->private = call; | ||
758 | |||
759 | return 0; | ||
683 | } | 760 | } |
684 | 761 | ||
685 | static ssize_t | 762 | static ssize_t |
@@ -877,8 +954,10 @@ static const struct file_operations ftrace_enable_fops = { | |||
877 | }; | 954 | }; |
878 | 955 | ||
879 | static const struct file_operations ftrace_event_format_fops = { | 956 | static const struct file_operations ftrace_event_format_fops = { |
880 | .open = tracing_open_generic, | 957 | .open = trace_format_open, |
881 | .read = event_format_read, | 958 | .read = seq_read, |
959 | .llseek = seq_lseek, | ||
960 | .release = seq_release, | ||
882 | }; | 961 | }; |
883 | 962 | ||
884 | static const struct file_operations ftrace_event_id_fops = { | 963 | static const struct file_operations ftrace_event_id_fops = { |
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index 6bff23625781..6f233698518e 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c | |||
@@ -507,7 +507,15 @@ get_return_for_leaf(struct trace_iterator *iter, | |||
507 | * if the output fails. | 507 | * if the output fails. |
508 | */ | 508 | */ |
509 | data->ent = *curr; | 509 | data->ent = *curr; |
510 | data->ret = *next; | 510 | /* |
511 | * If the next event is not a return type, then | ||
512 | * we only care about what type it is. Otherwise we can | ||
513 | * safely copy the entire event. | ||
514 | */ | ||
515 | if (next->ent.type == TRACE_GRAPH_RET) | ||
516 | data->ret = *next; | ||
517 | else | ||
518 | data->ret.ent.type = next->ent.type; | ||
511 | } | 519 | } |
512 | } | 520 | } |
513 | 521 | ||
diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index 0171060b5fd6..e67f05486087 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl | |||
@@ -159,6 +159,7 @@ my $section_regex; # Find the start of a section | |||
159 | my $function_regex; # Find the name of a function | 159 | my $function_regex; # Find the name of a function |
160 | # (return offset and func name) | 160 | # (return offset and func name) |
161 | my $mcount_regex; # Find the call site to mcount (return offset) | 161 | my $mcount_regex; # Find the call site to mcount (return offset) |
162 | my $mcount_adjust; # Address adjustment to mcount offset | ||
162 | my $alignment; # The .align value to use for $mcount_section | 163 | my $alignment; # The .align value to use for $mcount_section |
163 | my $section_type; # Section header plus possible alignment command | 164 | my $section_type; # Section header plus possible alignment command |
164 | my $can_use_local = 0; # If we can use local function references | 165 | my $can_use_local = 0; # If we can use local function references |
@@ -213,6 +214,7 @@ $section_regex = "Disassembly of section\\s+(\\S+):"; | |||
213 | $function_regex = "^([0-9a-fA-F]+)\\s+<(.*?)>:"; | 214 | $function_regex = "^([0-9a-fA-F]+)\\s+<(.*?)>:"; |
214 | $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\smcount\$"; | 215 | $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\smcount\$"; |
215 | $section_type = '@progbits'; | 216 | $section_type = '@progbits'; |
217 | $mcount_adjust = 0; | ||
216 | $type = ".long"; | 218 | $type = ".long"; |
217 | 219 | ||
218 | if ($arch eq "x86_64") { | 220 | if ($arch eq "x86_64") { |
@@ -351,6 +353,9 @@ if ($arch eq "x86_64") { | |||
351 | } elsif ($arch eq "microblaze") { | 353 | } elsif ($arch eq "microblaze") { |
352 | # Microblaze calls '_mcount' instead of plain 'mcount'. | 354 | # Microblaze calls '_mcount' instead of plain 'mcount'. |
353 | $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$"; | 355 | $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$"; |
356 | } elsif ($arch eq "blackfin") { | ||
357 | $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s__mcount\$"; | ||
358 | $mcount_adjust = -4; | ||
354 | } else { | 359 | } else { |
355 | die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD"; | 360 | die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD"; |
356 | } | 361 | } |
@@ -511,7 +516,7 @@ while (<IN>) { | |||
511 | } | 516 | } |
512 | # is this a call site to mcount? If so, record it to print later | 517 | # is this a call site to mcount? If so, record it to print later |
513 | if ($text_found && /$mcount_regex/) { | 518 | if ($text_found && /$mcount_regex/) { |
514 | push(@offsets, hex $1); | 519 | push(@offsets, (hex $1) + $mcount_adjust); |
515 | } | 520 | } |
516 | } | 521 | } |
517 | 522 | ||