aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace.c
diff options
context:
space:
mode:
authorSteven Rostedt <rostedt@goodmis.org>2008-08-01 12:26:41 -0400
committerIngo Molnar <mingo@elte.hu>2008-10-14 04:35:19 -0400
commitdd0e545f061f90099a3dcc13aa77e29c6295cf23 (patch)
tree91842e81cacd2ae785bf14b96f3f65af96985658 /kernel/trace/trace.c
parent2e2ca155cd2213b4f398031180fb3d399d5b7db9 (diff)
ftrace: printk formatting infrastructure
This patch adds a feature that can help kernel developers debug their code using ftrace. int ftrace_printk(const char *fmt, ...); This records into the ftrace buffer using printf formatting. The entry size in the buffers are still a fixed length. A new type has been added that allows for more entries to be used for a single recording. The start of the print is still the same as the other entries. It returns the number of characters written to the ftrace buffer. For example: Having a module with the following code: static int __init ftrace_print_test(void) { ftrace_printk("jiffies are %ld\n", jiffies); return 0; } Gives me: insmod-5441 3...1 7569us : ftrace_print_test: jiffies are 4296626666 for the latency_trace file and: insmod-5441 [03] 1959.370498: ftrace_print_test jiffies are 4296626666 for the trace file. Note: Only the infrastructure should go into the kernel. It is to help facilitate debugging for other kernel developers. Calls to ftrace_printk is not intended to be left in the kernel, and should be frowned upon just like scattering printks around in the code. But having this easily at your fingertips helps the debugging go faster and bugs be solved quicker. Maybe later on, we can hook this with markers and have their printf format be sucked into ftrace output. Signed-off-by: Steven Rostedt <srostedt@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/trace/trace.c')
-rw-r--r--kernel/trace/trace.c273
1 files changed, 244 insertions, 29 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 76dfe6d2466c..a917bea82715 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -197,12 +197,14 @@ unsigned long nsecs_to_usecs(unsigned long nsecs)
197 * NEED_RESCED - reschedule is requested 197 * NEED_RESCED - reschedule is requested
198 * HARDIRQ - inside an interrupt handler 198 * HARDIRQ - inside an interrupt handler
199 * SOFTIRQ - inside a softirq handler 199 * SOFTIRQ - inside a softirq handler
200 * CONT - multiple entries hold the trace item
200 */ 201 */
201enum trace_flag_type { 202enum trace_flag_type {
202 TRACE_FLAG_IRQS_OFF = 0x01, 203 TRACE_FLAG_IRQS_OFF = 0x01,
203 TRACE_FLAG_NEED_RESCHED = 0x02, 204 TRACE_FLAG_NEED_RESCHED = 0x02,
204 TRACE_FLAG_HARDIRQ = 0x04, 205 TRACE_FLAG_HARDIRQ = 0x04,
205 TRACE_FLAG_SOFTIRQ = 0x08, 206 TRACE_FLAG_SOFTIRQ = 0x08,
207 TRACE_FLAG_CONT = 0x10,
206}; 208};
207 209
208/* 210/*
@@ -1074,6 +1076,7 @@ enum trace_file_type {
1074 TRACE_FILE_LAT_FMT = 1, 1076 TRACE_FILE_LAT_FMT = 1,
1075}; 1077};
1076 1078
1079/* Return the current entry. */
1077static struct trace_entry * 1080static struct trace_entry *
1078trace_entry_idx(struct trace_array *tr, struct trace_array_cpu *data, 1081trace_entry_idx(struct trace_array *tr, struct trace_array_cpu *data,
1079 struct trace_iterator *iter, int cpu) 1082 struct trace_iterator *iter, int cpu)
@@ -1104,8 +1107,58 @@ trace_entry_idx(struct trace_array *tr, struct trace_array_cpu *data,
1104 return &array[iter->next_page_idx[cpu]]; 1107 return &array[iter->next_page_idx[cpu]];
1105} 1108}
1106 1109
1110/* Increment the index counter of an iterator by one */
1111static void trace_iterator_increment(struct trace_iterator *iter, int cpu)
1112{
1113 iter->idx++;
1114 iter->next_idx[cpu]++;
1115 iter->next_page_idx[cpu]++;
1116
1117 if (iter->next_page_idx[cpu] >= ENTRIES_PER_PAGE) {
1118 struct trace_array_cpu *data = iter->tr->data[cpu];
1119
1120 iter->next_page_idx[cpu] = 0;
1121 iter->next_page[cpu] =
1122 trace_next_list(data, iter->next_page[cpu]);
1123 }
1124}
1125
1107static struct trace_entry * 1126static struct trace_entry *
1108find_next_entry(struct trace_iterator *iter, int *ent_cpu) 1127trace_entry_next(struct trace_array *tr, struct trace_array_cpu *data,
1128 struct trace_iterator *iter, int cpu)
1129{
1130 struct list_head *next_page;
1131 struct trace_entry *ent;
1132 int idx, next_idx, next_page_idx;
1133
1134 ent = trace_entry_idx(tr, tr->data[cpu], iter, cpu);
1135
1136 if (likely(!ent || ent->type != TRACE_CONT))
1137 return ent;
1138
1139 /* save the iterator details */
1140 idx = iter->idx;
1141 next_idx = iter->next_idx[cpu];
1142 next_page_idx = iter->next_page_idx[cpu];
1143 next_page = iter->next_page[cpu];
1144
1145 /* find a real entry */
1146 do {
1147 trace_iterator_increment(iter, cpu);
1148 ent = trace_entry_idx(tr, tr->data[cpu], iter, cpu);
1149 } while (ent && ent->type != TRACE_CONT);
1150
1151 /* reset the iterator */
1152 iter->idx = idx;
1153 iter->next_idx[cpu] = next_idx;
1154 iter->next_page_idx[cpu] = next_page_idx;
1155 iter->next_page[cpu] = next_page;
1156
1157 return ent;
1158}
1159
1160static struct trace_entry *
1161__find_next_entry(struct trace_iterator *iter, int *ent_cpu, int inc)
1109{ 1162{
1110 struct trace_array *tr = iter->tr; 1163 struct trace_array *tr = iter->tr;
1111 struct trace_entry *ent, *next = NULL; 1164 struct trace_entry *ent, *next = NULL;
@@ -1115,7 +1168,23 @@ find_next_entry(struct trace_iterator *iter, int *ent_cpu)
1115 for_each_tracing_cpu(cpu) { 1168 for_each_tracing_cpu(cpu) {
1116 if (!head_page(tr->data[cpu])) 1169 if (!head_page(tr->data[cpu]))
1117 continue; 1170 continue;
1171
1118 ent = trace_entry_idx(tr, tr->data[cpu], iter, cpu); 1172 ent = trace_entry_idx(tr, tr->data[cpu], iter, cpu);
1173
1174 if (ent && ent->type == TRACE_CONT) {
1175 struct trace_array_cpu *data = tr->data[cpu];
1176
1177 if (!inc)
1178 ent = trace_entry_next(tr, data, iter, cpu);
1179 else {
1180 while (ent && ent->type == TRACE_CONT) {
1181 trace_iterator_increment(iter, cpu);
1182 ent = trace_entry_idx(tr, tr->data[cpu],
1183 iter, cpu);
1184 }
1185 }
1186 }
1187
1119 /* 1188 /*
1120 * Pick the entry with the smallest timestamp: 1189 * Pick the entry with the smallest timestamp:
1121 */ 1190 */
@@ -1131,25 +1200,39 @@ find_next_entry(struct trace_iterator *iter, int *ent_cpu)
1131 return next; 1200 return next;
1132} 1201}
1133 1202
1134static void trace_iterator_increment(struct trace_iterator *iter) 1203/* Find the next real entry, without updating the iterator itself */
1204static struct trace_entry *
1205find_next_entry(struct trace_iterator *iter, int *ent_cpu)
1135{ 1206{
1136 iter->idx++; 1207 return __find_next_entry(iter, ent_cpu, 0);
1137 iter->next_idx[iter->cpu]++; 1208}
1138 iter->next_page_idx[iter->cpu]++; 1209
1210/* Find the next real entry, and increment the iterator to the next entry */
1211static void *find_next_entry_inc(struct trace_iterator *iter)
1212{
1213 struct trace_entry *next;
1214 int next_cpu = -1;
1139 1215
1140 if (iter->next_page_idx[iter->cpu] >= ENTRIES_PER_PAGE) { 1216 next = __find_next_entry(iter, &next_cpu, 1);
1141 struct trace_array_cpu *data = iter->tr->data[iter->cpu];
1142 1217
1143 iter->next_page_idx[iter->cpu] = 0; 1218 iter->prev_ent = iter->ent;
1144 iter->next_page[iter->cpu] = 1219 iter->prev_cpu = iter->cpu;
1145 trace_next_list(data, iter->next_page[iter->cpu]); 1220
1146 } 1221 iter->ent = next;
1222 iter->cpu = next_cpu;
1223
1224 if (next)
1225 trace_iterator_increment(iter, iter->cpu);
1226
1227 return next ? iter : NULL;
1147} 1228}
1148 1229
1149static void trace_consume(struct trace_iterator *iter) 1230static void trace_consume(struct trace_iterator *iter)
1150{ 1231{
1151 struct trace_array_cpu *data = iter->tr->data[iter->cpu]; 1232 struct trace_array_cpu *data = iter->tr->data[iter->cpu];
1233 struct trace_entry *ent;
1152 1234
1235 again:
1153 data->trace_tail_idx++; 1236 data->trace_tail_idx++;
1154 if (data->trace_tail_idx >= ENTRIES_PER_PAGE) { 1237 if (data->trace_tail_idx >= ENTRIES_PER_PAGE) {
1155 data->trace_tail = trace_next_page(data, data->trace_tail); 1238 data->trace_tail = trace_next_page(data, data->trace_tail);
@@ -1160,25 +1243,11 @@ static void trace_consume(struct trace_iterator *iter)
1160 if (data->trace_head == data->trace_tail && 1243 if (data->trace_head == data->trace_tail &&
1161 data->trace_head_idx == data->trace_tail_idx) 1244 data->trace_head_idx == data->trace_tail_idx)
1162 data->trace_idx = 0; 1245 data->trace_idx = 0;
1163}
1164
1165static void *find_next_entry_inc(struct trace_iterator *iter)
1166{
1167 struct trace_entry *next;
1168 int next_cpu = -1;
1169
1170 next = find_next_entry(iter, &next_cpu);
1171
1172 iter->prev_ent = iter->ent;
1173 iter->prev_cpu = iter->cpu;
1174
1175 iter->ent = next;
1176 iter->cpu = next_cpu;
1177
1178 if (next)
1179 trace_iterator_increment(iter);
1180 1246
1181 return next ? iter : NULL; 1247 ent = trace_entry_idx(iter->tr, iter->tr->data[iter->cpu],
1248 iter, iter->cpu);
1249 if (ent && ent->type == TRACE_CONT)
1250 goto again;
1182} 1251}
1183 1252
1184static void *s_next(struct seq_file *m, void *v, loff_t *pos) 1253static void *s_next(struct seq_file *m, void *v, loff_t *pos)
@@ -1473,6 +1542,26 @@ lat_print_timestamp(struct trace_seq *s, unsigned long long abs_usecs,
1473 1542
1474static const char state_to_char[] = TASK_STATE_TO_CHAR_STR; 1543static const char state_to_char[] = TASK_STATE_TO_CHAR_STR;
1475 1544
1545static void
1546trace_seq_print_cont(struct trace_seq *s, struct trace_iterator *iter)
1547{
1548 struct trace_array *tr = iter->tr;
1549 struct trace_array_cpu *data = tr->data[iter->cpu];
1550 struct trace_entry *ent;
1551
1552 ent = trace_entry_idx(tr, data, iter, iter->cpu);
1553 if (!ent || ent->type != TRACE_CONT) {
1554 trace_seq_putc(s, '\n');
1555 return;
1556 }
1557
1558 do {
1559 trace_seq_printf(s, "%s", ent->cont.buf);
1560 trace_iterator_increment(iter, iter->cpu);
1561 ent = trace_entry_idx(tr, data, iter, iter->cpu);
1562 } while (ent && ent->type == TRACE_CONT);
1563}
1564
1476static int 1565static int
1477print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu) 1566print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu)
1478{ 1567{
@@ -1491,6 +1580,10 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu)
1491 1580
1492 if (!next_entry) 1581 if (!next_entry)
1493 next_entry = entry; 1582 next_entry = entry;
1583
1584 if (entry->type == TRACE_CONT)
1585 return 1;
1586
1494 rel_usecs = ns2usecs(next_entry->field.t - entry->field.t); 1587 rel_usecs = ns2usecs(next_entry->field.t - entry->field.t);
1495 abs_usecs = ns2usecs(entry->field.t - iter->tr->time_start); 1588 abs_usecs = ns2usecs(entry->field.t - iter->tr->time_start);
1496 1589
@@ -1550,6 +1643,12 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu)
1550 } 1643 }
1551 trace_seq_puts(s, "\n"); 1644 trace_seq_puts(s, "\n");
1552 break; 1645 break;
1646 case TRACE_PRINT:
1647 seq_print_ip_sym(s, field->print.ip, sym_flags);
1648 trace_seq_printf(s, ": %s", field->print.buf);
1649 if (field->flags && TRACE_FLAG_CONT)
1650 trace_seq_print_cont(s, iter);
1651 break;
1553 default: 1652 default:
1554 trace_seq_printf(s, "Unknown type %d\n", entry->type); 1653 trace_seq_printf(s, "Unknown type %d\n", entry->type);
1555 } 1654 }
@@ -1571,6 +1670,10 @@ static int print_trace_fmt(struct trace_iterator *iter)
1571 int i; 1670 int i;
1572 1671
1573 entry = iter->ent; 1672 entry = iter->ent;
1673
1674 if (entry->type == TRACE_CONT)
1675 return 1;
1676
1574 field = &entry->field; 1677 field = &entry->field;
1575 1678
1576 comm = trace_find_cmdline(iter->ent->field.pid); 1679 comm = trace_find_cmdline(iter->ent->field.pid);
@@ -1653,6 +1756,12 @@ static int print_trace_fmt(struct trace_iterator *iter)
1653 if (!ret) 1756 if (!ret)
1654 return 0; 1757 return 0;
1655 break; 1758 break;
1759 case TRACE_PRINT:
1760 seq_print_ip_sym(s, field->print.ip, sym_flags);
1761 trace_seq_printf(s, ": %s", field->print.buf);
1762 if (field->flags && TRACE_FLAG_CONT)
1763 trace_seq_print_cont(s, iter);
1764 break;
1656 } 1765 }
1657 return 1; 1766 return 1;
1658} 1767}
@@ -1666,6 +1775,10 @@ static int print_raw_fmt(struct trace_iterator *iter)
1666 int S, T; 1775 int S, T;
1667 1776
1668 entry = iter->ent; 1777 entry = iter->ent;
1778
1779 if (entry->type == TRACE_CONT)
1780 return 1;
1781
1669 field = &entry->field; 1782 field = &entry->field;
1670 1783
1671 ret = trace_seq_printf(s, "%d %d %llu ", 1784 ret = trace_seq_printf(s, "%d %d %llu ",
@@ -1708,6 +1821,12 @@ static int print_raw_fmt(struct trace_iterator *iter)
1708 if (!ret) 1821 if (!ret)
1709 return 0; 1822 return 0;
1710 break; 1823 break;
1824 case TRACE_PRINT:
1825 trace_seq_printf(s, "# %lx %s",
1826 field->print.ip, field->print.buf);
1827 if (field->flags && TRACE_FLAG_CONT)
1828 trace_seq_print_cont(s, iter);
1829 break;
1711 } 1830 }
1712 return 1; 1831 return 1;
1713} 1832}
@@ -1733,6 +1852,10 @@ static int print_hex_fmt(struct trace_iterator *iter)
1733 int S, T; 1852 int S, T;
1734 1853
1735 entry = iter->ent; 1854 entry = iter->ent;
1855
1856 if (entry->type == TRACE_CONT)
1857 return 1;
1858
1736 field = &entry->field; 1859 field = &entry->field;
1737 1860
1738 SEQ_PUT_HEX_FIELD_RET(s, field->pid); 1861 SEQ_PUT_HEX_FIELD_RET(s, field->pid);
@@ -1778,6 +1901,10 @@ static int print_bin_fmt(struct trace_iterator *iter)
1778 struct trace_field *field; 1901 struct trace_field *field;
1779 1902
1780 entry = iter->ent; 1903 entry = iter->ent;
1904
1905 if (entry->type == TRACE_CONT)
1906 return 1;
1907
1781 field = &entry->field; 1908 field = &entry->field;
1782 1909
1783 SEQ_PUT_FIELD_RET(s, field->pid); 1910 SEQ_PUT_FIELD_RET(s, field->pid);
@@ -2943,6 +3070,94 @@ static __init void tracer_init_debugfs(void)
2943#endif 3070#endif
2944} 3071}
2945 3072
3073#define TRACE_BUF_SIZE 1024
3074#define TRACE_PRINT_BUF_SIZE \
3075 (sizeof(struct trace_field) - offsetof(struct trace_field, print.buf))
3076#define TRACE_CONT_BUF_SIZE sizeof(struct trace_field)
3077
3078/**
3079 * ftrace_printk - printf formatting in the ftrace buffer
3080 * @fmt - the printf format for printing.
3081 *
3082 * Note: __ftrace_printk is an internal function for ftrace_printk and
3083 * the @ip is passed in via the ftrace_printk macro.
3084 *
3085 * This function allows a kernel developer to debug fast path sections
3086 * that printk is not appropriate for. By scattering in various
3087 * printk like tracing in the code, a developer can quickly see
3088 * where problems are occurring.
3089 *
3090 * This is intended as a debugging tool for the developer only.
3091 * Please reframe from leaving ftrace_printks scattered around in
3092 * your code.
3093 */
3094int __ftrace_printk(unsigned long ip, const char *fmt, ...)
3095{
3096 struct trace_array *tr = &global_trace;
3097 static DEFINE_SPINLOCK(trace_buf_lock);
3098 static char trace_buf[TRACE_BUF_SIZE];
3099 struct trace_array_cpu *data;
3100 struct trace_entry *entry;
3101 unsigned long flags;
3102 long disabled;
3103 va_list ap;
3104 int cpu, len = 0, write, written = 0;
3105
3106 if (likely(!ftrace_function_enabled))
3107 return 0;
3108
3109 local_irq_save(flags);
3110 cpu = raw_smp_processor_id();
3111 data = tr->data[cpu];
3112 disabled = atomic_inc_return(&data->disabled);
3113
3114 if (unlikely(disabled != 1 || !ftrace_function_enabled))
3115 goto out;
3116
3117 spin_lock(&trace_buf_lock);
3118 va_start(ap, fmt);
3119 len = vsnprintf(trace_buf, TRACE_BUF_SIZE, fmt, ap);
3120 va_end(ap);
3121
3122 len = min(len, TRACE_BUF_SIZE-1);
3123 trace_buf[len] = 0;
3124
3125 __raw_spin_lock(&data->lock);
3126 entry = tracing_get_trace_entry(tr, data);
3127 tracing_generic_entry_update(entry, flags);
3128 entry->type = TRACE_PRINT;
3129 entry->field.print.ip = ip;
3130
3131 write = min(len, (int)(TRACE_PRINT_BUF_SIZE-1));
3132
3133 memcpy(&entry->field.print.buf, trace_buf, write);
3134 entry->field.print.buf[write] = 0;
3135 written = write;
3136
3137 if (written != len)
3138 entry->field.flags |= TRACE_FLAG_CONT;
3139
3140 while (written != len) {
3141 entry = tracing_get_trace_entry(tr, data);
3142
3143 entry->type = TRACE_CONT;
3144 write = min(len - written, (int)(TRACE_CONT_BUF_SIZE-1));
3145 memcpy(&entry->cont.buf, trace_buf+written, write);
3146 entry->cont.buf[write] = 0;
3147 written += write;
3148 }
3149 __raw_spin_unlock(&data->lock);
3150
3151 spin_unlock(&trace_buf_lock);
3152
3153 out:
3154 atomic_dec(&data->disabled);
3155 local_irq_restore(flags);
3156
3157 return len;
3158}
3159EXPORT_SYMBOL_GPL(__ftrace_printk);
3160
2946static int trace_alloc_page(void) 3161static int trace_alloc_page(void)
2947{ 3162{
2948 struct trace_array_cpu *data; 3163 struct trace_array_cpu *data;