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