diff options
| author | Steven Rostedt <srostedt@redhat.com> | 2008-05-12 15:20:46 -0400 |
|---|---|---|
| committer | Thomas Gleixner <tglx@linutronix.de> | 2008-05-23 14:41:46 -0400 |
| commit | 214023c3d13a71525e463b5e54e360b926b4dc90 (patch) | |
| tree | 6fe6f3e513d976b32eb07f60810ccf336daf1f6b /kernel/trace | |
| parent | 93a588f459da134be6ab17c4104e28441beb0d22 (diff) | |
ftrace: add a buffer for output
Later patches will need to print the same things as the seq output
does. But those outputs will not use the seq utility. This patch
adds a buffer to the iterator, that can be used by either the
seq utility or other output.
Signed-off-by: Steven Rostedt <srostedt@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/trace')
| -rw-r--r-- | kernel/trace/trace.c | 202 | ||||
| -rw-r--r-- | kernel/trace/trace.h | 6 |
2 files changed, 140 insertions, 68 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 777b859e1c2e..d39f4faec7c3 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
| @@ -169,6 +169,66 @@ void *head_page(struct trace_array_cpu *data) | |||
| 169 | return page_address(page); | 169 | return page_address(page); |
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | static notrace int | ||
| 173 | trace_seq_printf(struct trace_seq *s, const char *fmt, ...) | ||
| 174 | { | ||
| 175 | int len = (PAGE_SIZE - 1) - s->len; | ||
| 176 | va_list ap; | ||
| 177 | |||
| 178 | if (!len) | ||
| 179 | return 0; | ||
| 180 | |||
| 181 | va_start(ap, fmt); | ||
| 182 | len = vsnprintf(s->buffer + s->len, len, fmt, ap); | ||
| 183 | va_end(ap); | ||
| 184 | |||
| 185 | s->len += len; | ||
| 186 | |||
| 187 | return len; | ||
| 188 | } | ||
| 189 | |||
| 190 | static notrace int | ||
| 191 | trace_seq_puts(struct trace_seq *s, const char *str) | ||
| 192 | { | ||
| 193 | int len = strlen(str); | ||
| 194 | |||
| 195 | if (len > ((PAGE_SIZE - 1) - s->len)) | ||
| 196 | len = (PAGE_SIZE - 1) - s->len; | ||
| 197 | |||
| 198 | memcpy(s->buffer + s->len, str, len); | ||
| 199 | s->len += len; | ||
| 200 | |||
| 201 | return len; | ||
| 202 | } | ||
| 203 | |||
| 204 | static notrace int | ||
| 205 | trace_seq_putc(struct trace_seq *s, unsigned char c) | ||
| 206 | { | ||
| 207 | if (s->len >= (PAGE_SIZE - 1)) | ||
| 208 | return 0; | ||
| 209 | |||
| 210 | s->buffer[s->len++] = c; | ||
| 211 | |||
| 212 | return 1; | ||
| 213 | } | ||
| 214 | |||
| 215 | static notrace void | ||
| 216 | trace_seq_reset(struct trace_seq *s) | ||
| 217 | { | ||
| 218 | s->len = 0; | ||
| 219 | } | ||
| 220 | |||
| 221 | static notrace void | ||
| 222 | trace_print_seq(struct seq_file *m, struct trace_seq *s) | ||
| 223 | { | ||
| 224 | int len = s->len >= PAGE_SIZE ? PAGE_SIZE - 1 : s->len; | ||
| 225 | |||
| 226 | s->buffer[len] = 0; | ||
| 227 | seq_puts(m, s->buffer); | ||
| 228 | |||
| 229 | trace_seq_reset(s); | ||
| 230 | } | ||
| 231 | |||
| 172 | notrace static void | 232 | notrace static void |
| 173 | flip_trace(struct trace_array_cpu *tr1, struct trace_array_cpu *tr2) | 233 | flip_trace(struct trace_array_cpu *tr1, struct trace_array_cpu *tr2) |
| 174 | { | 234 | { |
| @@ -756,25 +816,26 @@ static void s_stop(struct seq_file *m, void *p) | |||
| 756 | } | 816 | } |
| 757 | 817 | ||
| 758 | static void | 818 | static void |
| 759 | seq_print_sym_short(struct seq_file *m, const char *fmt, unsigned long address) | 819 | seq_print_sym_short(struct trace_seq *s, const char *fmt, unsigned long address) |
| 760 | { | 820 | { |
| 761 | #ifdef CONFIG_KALLSYMS | 821 | #ifdef CONFIG_KALLSYMS |
| 762 | char str[KSYM_SYMBOL_LEN]; | 822 | char str[KSYM_SYMBOL_LEN]; |
| 763 | 823 | ||
| 764 | kallsyms_lookup(address, NULL, NULL, NULL, str); | 824 | kallsyms_lookup(address, NULL, NULL, NULL, str); |
| 765 | 825 | ||
| 766 | seq_printf(m, fmt, str); | 826 | trace_seq_printf(s, fmt, str); |
| 767 | #endif | 827 | #endif |
| 768 | } | 828 | } |
| 769 | 829 | ||
| 770 | static void | 830 | static void |
| 771 | seq_print_sym_offset(struct seq_file *m, const char *fmt, unsigned long address) | 831 | seq_print_sym_offset(struct trace_seq *s, const char *fmt, |
| 832 | unsigned long address) | ||
| 772 | { | 833 | { |
| 773 | #ifdef CONFIG_KALLSYMS | 834 | #ifdef CONFIG_KALLSYMS |
| 774 | char str[KSYM_SYMBOL_LEN]; | 835 | char str[KSYM_SYMBOL_LEN]; |
| 775 | 836 | ||
| 776 | sprint_symbol(str, address); | 837 | sprint_symbol(str, address); |
| 777 | seq_printf(m, fmt, str); | 838 | trace_seq_printf(s, fmt, str); |
| 778 | #endif | 839 | #endif |
| 779 | } | 840 | } |
| 780 | 841 | ||
| @@ -785,20 +846,20 @@ seq_print_sym_offset(struct seq_file *m, const char *fmt, unsigned long address) | |||
| 785 | #endif | 846 | #endif |
| 786 | 847 | ||
| 787 | static notrace void | 848 | static notrace void |
| 788 | seq_print_ip_sym(struct seq_file *m, unsigned long ip, unsigned long sym_flags) | 849 | seq_print_ip_sym(struct trace_seq *s, unsigned long ip, unsigned long sym_flags) |
| 789 | { | 850 | { |
| 790 | if (!ip) { | 851 | if (!ip) { |
| 791 | seq_printf(m, "0"); | 852 | trace_seq_printf(s, "0"); |
| 792 | return; | 853 | return; |
| 793 | } | 854 | } |
| 794 | 855 | ||
| 795 | if (sym_flags & TRACE_ITER_SYM_OFFSET) | 856 | if (sym_flags & TRACE_ITER_SYM_OFFSET) |
| 796 | seq_print_sym_offset(m, "%s", ip); | 857 | seq_print_sym_offset(s, "%s", ip); |
| 797 | else | 858 | else |
| 798 | seq_print_sym_short(m, "%s", ip); | 859 | seq_print_sym_short(s, "%s", ip); |
| 799 | 860 | ||
| 800 | if (sym_flags & TRACE_ITER_SYM_ADDR) | 861 | if (sym_flags & TRACE_ITER_SYM_ADDR) |
| 801 | seq_printf(m, " <" IP_FMT ">", ip); | 862 | trace_seq_printf(s, " <" IP_FMT ">", ip); |
| 802 | } | 863 | } |
| 803 | 864 | ||
| 804 | static notrace void print_lat_help_header(struct seq_file *m) | 865 | static notrace void print_lat_help_header(struct seq_file *m) |
| @@ -881,9 +942,11 @@ print_trace_header(struct seq_file *m, struct trace_iterator *iter) | |||
| 881 | 942 | ||
| 882 | if (data->critical_start) { | 943 | if (data->critical_start) { |
| 883 | seq_puts(m, " => started at: "); | 944 | seq_puts(m, " => started at: "); |
| 884 | seq_print_ip_sym(m, data->critical_start, sym_flags); | 945 | seq_print_ip_sym(&iter->seq, data->critical_start, sym_flags); |
| 946 | trace_print_seq(m, &iter->seq); | ||
| 885 | seq_puts(m, "\n => ended at: "); | 947 | seq_puts(m, "\n => ended at: "); |
| 886 | seq_print_ip_sym(m, data->critical_end, sym_flags); | 948 | seq_print_ip_sym(&iter->seq, data->critical_end, sym_flags); |
| 949 | trace_print_seq(m, &iter->seq); | ||
| 887 | seq_puts(m, "\n"); | 950 | seq_puts(m, "\n"); |
| 888 | } | 951 | } |
| 889 | 952 | ||
| @@ -891,61 +954,61 @@ print_trace_header(struct seq_file *m, struct trace_iterator *iter) | |||
| 891 | } | 954 | } |
| 892 | 955 | ||
| 893 | static notrace void | 956 | static notrace void |
| 894 | lat_print_generic(struct seq_file *m, struct trace_entry *entry, int cpu) | 957 | lat_print_generic(struct trace_seq *s, struct trace_entry *entry, int cpu) |
| 895 | { | 958 | { |
| 896 | int hardirq, softirq; | 959 | int hardirq, softirq; |
| 897 | char *comm; | 960 | char *comm; |
| 898 | 961 | ||
| 899 | comm = trace_find_cmdline(entry->pid); | 962 | comm = trace_find_cmdline(entry->pid); |
| 900 | 963 | ||
| 901 | seq_printf(m, "%8.8s-%-5d ", comm, entry->pid); | 964 | trace_seq_printf(s, "%8.8s-%-5d ", comm, entry->pid); |
| 902 | seq_printf(m, "%d", cpu); | 965 | trace_seq_printf(s, "%d", cpu); |
| 903 | seq_printf(m, "%c%c", | 966 | trace_seq_printf(s, "%c%c", |
| 904 | (entry->flags & TRACE_FLAG_IRQS_OFF) ? 'd' : '.', | 967 | (entry->flags & TRACE_FLAG_IRQS_OFF) ? 'd' : '.', |
| 905 | ((entry->flags & TRACE_FLAG_NEED_RESCHED) ? 'N' : '.')); | 968 | ((entry->flags & TRACE_FLAG_NEED_RESCHED) ? 'N' : '.')); |
| 906 | 969 | ||
| 907 | hardirq = entry->flags & TRACE_FLAG_HARDIRQ; | 970 | hardirq = entry->flags & TRACE_FLAG_HARDIRQ; |
| 908 | softirq = entry->flags & TRACE_FLAG_SOFTIRQ; | 971 | softirq = entry->flags & TRACE_FLAG_SOFTIRQ; |
| 909 | if (hardirq && softirq) | 972 | if (hardirq && softirq) |
| 910 | seq_putc(m, 'H'); | 973 | trace_seq_putc(s, 'H'); |
| 911 | else { | 974 | else { |
| 912 | if (hardirq) | 975 | if (hardirq) |
| 913 | seq_putc(m, 'h'); | 976 | trace_seq_putc(s, 'h'); |
| 914 | else { | 977 | else { |
| 915 | if (softirq) | 978 | if (softirq) |
| 916 | seq_putc(m, 's'); | 979 | trace_seq_putc(s, 's'); |
| 917 | else | 980 | else |
| 918 | seq_putc(m, '.'); | 981 | trace_seq_putc(s, '.'); |
| 919 | } | 982 | } |
| 920 | } | 983 | } |
| 921 | 984 | ||
| 922 | if (entry->preempt_count) | 985 | if (entry->preempt_count) |
| 923 | seq_printf(m, "%x", entry->preempt_count); | 986 | trace_seq_printf(s, "%x", entry->preempt_count); |
| 924 | else | 987 | else |
| 925 | seq_puts(m, "."); | 988 | trace_seq_puts(s, "."); |
| 926 | } | 989 | } |
| 927 | 990 | ||
| 928 | unsigned long preempt_mark_thresh = 100; | 991 | unsigned long preempt_mark_thresh = 100; |
| 929 | 992 | ||
| 930 | static notrace void | 993 | static notrace void |
| 931 | lat_print_timestamp(struct seq_file *m, unsigned long long abs_usecs, | 994 | lat_print_timestamp(struct trace_seq *s, unsigned long long abs_usecs, |
| 932 | unsigned long rel_usecs) | 995 | unsigned long rel_usecs) |
| 933 | { | 996 | { |
| 934 | seq_printf(m, " %4lldus", abs_usecs); | 997 | trace_seq_printf(s, " %4lldus", abs_usecs); |
| 935 | if (rel_usecs > preempt_mark_thresh) | 998 | if (rel_usecs > preempt_mark_thresh) |
| 936 | seq_puts(m, "!: "); | 999 | trace_seq_puts(s, "!: "); |
| 937 | else if (rel_usecs > 1) | 1000 | else if (rel_usecs > 1) |
| 938 | seq_puts(m, "+: "); | 1001 | trace_seq_puts(s, "+: "); |
| 939 | else | 1002 | else |
| 940 | seq_puts(m, " : "); | 1003 | trace_seq_puts(s, " : "); |
| 941 | } | 1004 | } |
| 942 | 1005 | ||
| 943 | static const char state_to_char[] = TASK_STATE_TO_CHAR_STR; | 1006 | static const char state_to_char[] = TASK_STATE_TO_CHAR_STR; |
| 944 | 1007 | ||
| 945 | static notrace void | 1008 | static notrace void |
| 946 | print_lat_fmt(struct seq_file *m, struct trace_iterator *iter, | 1009 | print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu) |
| 947 | unsigned int trace_idx, int cpu) | ||
| 948 | { | 1010 | { |
| 1011 | struct trace_seq *s = &iter->seq; | ||
| 949 | unsigned long sym_flags = (trace_flags & TRACE_ITER_SYM_MASK); | 1012 | unsigned long sym_flags = (trace_flags & TRACE_ITER_SYM_MASK); |
| 950 | struct trace_entry *next_entry = find_next_entry(iter, NULL); | 1013 | struct trace_entry *next_entry = find_next_entry(iter, NULL); |
| 951 | unsigned long verbose = (trace_flags & TRACE_ITER_VERBOSE); | 1014 | unsigned long verbose = (trace_flags & TRACE_ITER_VERBOSE); |
| @@ -962,39 +1025,40 @@ print_lat_fmt(struct seq_file *m, struct trace_iterator *iter, | |||
| 962 | 1025 | ||
| 963 | if (verbose) { | 1026 | if (verbose) { |
| 964 | comm = trace_find_cmdline(entry->pid); | 1027 | comm = trace_find_cmdline(entry->pid); |
| 965 | seq_printf(m, "%16s %5d %d %d %08x %08x [%08lx]" | 1028 | trace_seq_printf(s, "%16s %5d %d %d %08x %08x [%08lx]" |
| 966 | " %ld.%03ldms (+%ld.%03ldms): ", | 1029 | " %ld.%03ldms (+%ld.%03ldms): ", |
| 967 | comm, | 1030 | comm, |
| 968 | entry->pid, cpu, entry->flags, | 1031 | entry->pid, cpu, entry->flags, |
| 969 | entry->preempt_count, trace_idx, | 1032 | entry->preempt_count, trace_idx, |
| 970 | ns2usecs(entry->t), | 1033 | ns2usecs(entry->t), |
| 971 | abs_usecs/1000, | 1034 | abs_usecs/1000, |
| 972 | abs_usecs % 1000, rel_usecs/1000, rel_usecs % 1000); | 1035 | abs_usecs % 1000, rel_usecs/1000, |
| 1036 | rel_usecs % 1000); | ||
| 973 | } else { | 1037 | } else { |
| 974 | lat_print_generic(m, entry, cpu); | 1038 | lat_print_generic(s, entry, cpu); |
| 975 | lat_print_timestamp(m, abs_usecs, rel_usecs); | 1039 | lat_print_timestamp(s, abs_usecs, rel_usecs); |
| 976 | } | 1040 | } |
| 977 | switch (entry->type) { | 1041 | switch (entry->type) { |
| 978 | case TRACE_FN: | 1042 | case TRACE_FN: |
| 979 | seq_print_ip_sym(m, entry->fn.ip, sym_flags); | 1043 | seq_print_ip_sym(s, entry->fn.ip, sym_flags); |
| 980 | seq_puts(m, " ("); | 1044 | trace_seq_puts(s, " ("); |
| 981 | seq_print_ip_sym(m, entry->fn.parent_ip, sym_flags); | 1045 | seq_print_ip_sym(s, entry->fn.parent_ip, sym_flags); |
| 982 | seq_puts(m, ")\n"); | 1046 | trace_seq_puts(s, ")\n"); |
| 983 | break; | 1047 | break; |
| 984 | case TRACE_CTX: | 1048 | case TRACE_CTX: |
| 985 | S = entry->ctx.prev_state < sizeof(state_to_char) ? | 1049 | S = entry->ctx.prev_state < sizeof(state_to_char) ? |
| 986 | state_to_char[entry->ctx.prev_state] : 'X'; | 1050 | state_to_char[entry->ctx.prev_state] : 'X'; |
| 987 | comm = trace_find_cmdline(entry->ctx.next_pid); | 1051 | comm = trace_find_cmdline(entry->ctx.next_pid); |
| 988 | seq_printf(m, " %d:%d:%c --> %d:%d %s\n", | 1052 | trace_seq_printf(s, " %d:%d:%c --> %d:%d %s\n", |
| 989 | entry->ctx.prev_pid, | 1053 | entry->ctx.prev_pid, |
| 990 | entry->ctx.prev_prio, | 1054 | entry->ctx.prev_prio, |
| 991 | S, | 1055 | S, |
| 992 | entry->ctx.next_pid, | 1056 | entry->ctx.next_pid, |
| 993 | entry->ctx.next_prio, | 1057 | entry->ctx.next_prio, |
| 994 | comm); | 1058 | comm); |
| 995 | break; | 1059 | break; |
| 996 | default: | 1060 | default: |
| 997 | seq_printf(m, "Unknown type %d\n", entry->type); | 1061 | trace_seq_printf(s, "Unknown type %d\n", entry->type); |
| 998 | } | 1062 | } |
| 999 | } | 1063 | } |
| 1000 | 1064 | ||
| @@ -1026,8 +1090,9 @@ static notrace void sync_time_offset(struct trace_iterator *iter) | |||
| 1026 | } | 1090 | } |
| 1027 | 1091 | ||
| 1028 | static notrace void | 1092 | static notrace void |
| 1029 | print_trace_fmt(struct seq_file *m, struct trace_iterator *iter) | 1093 | print_trace_fmt(struct trace_iterator *iter) |
| 1030 | { | 1094 | { |
| 1095 | struct trace_seq *s = &iter->seq; | ||
| 1031 | unsigned long sym_flags = (trace_flags & TRACE_ITER_SYM_MASK); | 1096 | unsigned long sym_flags = (trace_flags & TRACE_ITER_SYM_MASK); |
| 1032 | struct trace_entry *entry; | 1097 | struct trace_entry *entry; |
| 1033 | unsigned long usec_rem; | 1098 | unsigned long usec_rem; |
| @@ -1045,29 +1110,29 @@ print_trace_fmt(struct seq_file *m, struct trace_iterator *iter) | |||
| 1045 | usec_rem = do_div(t, 1000000ULL); | 1110 | usec_rem = do_div(t, 1000000ULL); |
| 1046 | secs = (unsigned long)t; | 1111 | secs = (unsigned long)t; |
| 1047 | 1112 | ||
| 1048 | seq_printf(m, "%16s-%-5d ", comm, entry->pid); | 1113 | trace_seq_printf(s, "%16s-%-5d ", comm, entry->pid); |
| 1049 | seq_printf(m, "[%02d] ", iter->cpu); | 1114 | trace_seq_printf(s, "[%02d] ", iter->cpu); |
| 1050 | seq_printf(m, "%5lu.%06lu: ", secs, usec_rem); | 1115 | trace_seq_printf(s, "%5lu.%06lu: ", secs, usec_rem); |
| 1051 | 1116 | ||
| 1052 | switch (entry->type) { | 1117 | switch (entry->type) { |
| 1053 | case TRACE_FN: | 1118 | case TRACE_FN: |
| 1054 | seq_print_ip_sym(m, entry->fn.ip, sym_flags); | 1119 | seq_print_ip_sym(s, entry->fn.ip, sym_flags); |
| 1055 | if ((sym_flags & TRACE_ITER_PRINT_PARENT) && | 1120 | if ((sym_flags & TRACE_ITER_PRINT_PARENT) && |
| 1056 | entry->fn.parent_ip) { | 1121 | entry->fn.parent_ip) { |
| 1057 | seq_printf(m, " <-"); | 1122 | trace_seq_printf(s, " <-"); |
| 1058 | seq_print_ip_sym(m, entry->fn.parent_ip, sym_flags); | 1123 | seq_print_ip_sym(s, entry->fn.parent_ip, sym_flags); |
| 1059 | } | 1124 | } |
| 1060 | seq_printf(m, "\n"); | 1125 | trace_seq_printf(s, "\n"); |
| 1061 | break; | 1126 | break; |
| 1062 | case TRACE_CTX: | 1127 | case TRACE_CTX: |
| 1063 | S = entry->ctx.prev_state < sizeof(state_to_char) ? | 1128 | S = entry->ctx.prev_state < sizeof(state_to_char) ? |
| 1064 | state_to_char[entry->ctx.prev_state] : 'X'; | 1129 | state_to_char[entry->ctx.prev_state] : 'X'; |
| 1065 | seq_printf(m, " %d:%d:%c ==> %d:%d\n", | 1130 | trace_seq_printf(s, " %d:%d:%c ==> %d:%d\n", |
| 1066 | entry->ctx.prev_pid, | 1131 | entry->ctx.prev_pid, |
| 1067 | entry->ctx.prev_prio, | 1132 | entry->ctx.prev_prio, |
| 1068 | S, | 1133 | S, |
| 1069 | entry->ctx.next_pid, | 1134 | entry->ctx.next_pid, |
| 1070 | entry->ctx.next_prio); | 1135 | entry->ctx.next_prio); |
| 1071 | break; | 1136 | break; |
| 1072 | } | 1137 | } |
| 1073 | } | 1138 | } |
| @@ -1108,9 +1173,10 @@ static int s_show(struct seq_file *m, void *v) | |||
| 1108 | } | 1173 | } |
| 1109 | } else { | 1174 | } else { |
| 1110 | if (iter->iter_flags & TRACE_FILE_LAT_FMT) | 1175 | if (iter->iter_flags & TRACE_FILE_LAT_FMT) |
| 1111 | print_lat_fmt(m, iter, iter->idx, iter->cpu); | 1176 | print_lat_fmt(iter, iter->idx, iter->cpu); |
| 1112 | else | 1177 | else |
| 1113 | print_trace_fmt(m, iter); | 1178 | print_trace_fmt(iter); |
| 1179 | trace_print_seq(m, &iter->seq); | ||
| 1114 | } | 1180 | } |
| 1115 | 1181 | ||
| 1116 | return 0; | 1182 | return 0; |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 0ce127455b4b..f5b32ca0b457 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
| @@ -111,11 +111,17 @@ struct tracer { | |||
| 111 | int print_max; | 111 | int print_max; |
| 112 | }; | 112 | }; |
| 113 | 113 | ||
| 114 | struct trace_seq { | ||
| 115 | unsigned char buffer[PAGE_SIZE]; | ||
| 116 | unsigned int len; | ||
| 117 | }; | ||
| 118 | |||
| 114 | /* | 119 | /* |
| 115 | * Trace iterator - used by printout routines who present trace | 120 | * Trace iterator - used by printout routines who present trace |
| 116 | * results to users and which routines might sleep, etc: | 121 | * results to users and which routines might sleep, etc: |
| 117 | */ | 122 | */ |
| 118 | struct trace_iterator { | 123 | struct trace_iterator { |
| 124 | struct trace_seq seq; | ||
| 119 | struct trace_array *tr; | 125 | struct trace_array *tr; |
| 120 | struct tracer *trace; | 126 | struct tracer *trace; |
| 121 | 127 | ||
