Skip to content

Commit d40dbb6

Browse files
committed
ring-buffer: Add interrupt information to dump of data sub-buffer
When the ring buffer timestamp verifier triggers, it dumps the content of the sub-buffer. But currently it only dumps the timestamps and the offset of the data as well as the deltas. It would be even more informative if the event data also showed the interrupt context level it was in. That is, if each event showed that the event was written in normal, softirq, irq or NMI context. Then a better idea about how the events may have been interrupted from each other. As the payload of the ring buffer is really a black box of the ring buffer, just assume that if the payload is larger than a trace entry, that it is a trace entry. As trace entries have the interrupt context information saved in a flags field, look at that location and report the output of the flags. If the payload is not a trace entry, there's no way to really know, and the information will be garbage. But that's OK, because this is for debugging only (this output is not used in production as the buffer check that calls it causes a huge overhead to the tracing). This information, when available, is crucial for debugging timestamp issues. If it's garbage, it will also be pretty obvious that its garbage too. As this output usually happens in kselftests of the tracing code, the user will know what the payload is at the time. Link: https://lore.kernel.org/linux-trace-kernel/[email protected] Cc: Masami Hiramatsu <[email protected]> Cc: Mark Rutland <[email protected]> Cc: Mathieu Desnoyers <[email protected]> Suggested-by: Joel Fernandes (Google) <[email protected]> Signed-off-by: Steven Rostedt (Google) <[email protected]>
1 parent c84897c commit d40dbb6

File tree

1 file changed

+75
-4
lines changed

1 file changed

+75
-4
lines changed

kernel/trace/ring_buffer.c

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3185,6 +3185,76 @@ EXPORT_SYMBOL_GPL(ring_buffer_unlock_commit);
31853185
#define CHECK_FULL_PAGE 1L
31863186

31873187
#ifdef CONFIG_RING_BUFFER_VALIDATE_TIME_DELTAS
3188+
3189+
static const char *show_irq_str(int bits)
3190+
{
3191+
const char *type[] = {
3192+
".", // 0
3193+
"s", // 1
3194+
"h", // 2
3195+
"Hs", // 3
3196+
"n", // 4
3197+
"Ns", // 5
3198+
"Nh", // 6
3199+
"NHs", // 7
3200+
};
3201+
3202+
return type[bits];
3203+
}
3204+
3205+
/* Assume this is an trace event */
3206+
static const char *show_flags(struct ring_buffer_event *event)
3207+
{
3208+
struct trace_entry *entry;
3209+
int bits = 0;
3210+
3211+
if (rb_event_data_length(event) - RB_EVNT_HDR_SIZE < sizeof(*entry))
3212+
return "X";
3213+
3214+
entry = ring_buffer_event_data(event);
3215+
3216+
if (entry->flags & TRACE_FLAG_SOFTIRQ)
3217+
bits |= 1;
3218+
3219+
if (entry->flags & TRACE_FLAG_HARDIRQ)
3220+
bits |= 2;
3221+
3222+
if (entry->flags & TRACE_FLAG_NMI)
3223+
bits |= 4;
3224+
3225+
return show_irq_str(bits);
3226+
}
3227+
3228+
static const char *show_irq(struct ring_buffer_event *event)
3229+
{
3230+
struct trace_entry *entry;
3231+
3232+
if (rb_event_data_length(event) - RB_EVNT_HDR_SIZE < sizeof(*entry))
3233+
return "";
3234+
3235+
entry = ring_buffer_event_data(event);
3236+
if (entry->flags & TRACE_FLAG_IRQS_OFF)
3237+
return "d";
3238+
return "";
3239+
}
3240+
3241+
static const char *show_interrupt_level(void)
3242+
{
3243+
unsigned long pc = preempt_count();
3244+
unsigned char level = 0;
3245+
3246+
if (pc & SOFTIRQ_OFFSET)
3247+
level |= 1;
3248+
3249+
if (pc & HARDIRQ_MASK)
3250+
level |= 2;
3251+
3252+
if (pc & NMI_MASK)
3253+
level |= 4;
3254+
3255+
return show_irq_str(level);
3256+
}
3257+
31883258
static void dump_buffer_page(struct buffer_data_page *bpage,
31893259
struct rb_event_info *info,
31903260
unsigned long tail)
@@ -3224,8 +3294,9 @@ static void dump_buffer_page(struct buffer_data_page *bpage,
32243294

32253295
case RINGBUF_TYPE_DATA:
32263296
ts += event->time_delta;
3227-
pr_warn(" 0x%x: [%lld] delta:%d\n",
3228-
e, ts, event->time_delta);
3297+
pr_warn(" 0x%x: [%lld] delta:%d %s%s\n",
3298+
e, ts, event->time_delta,
3299+
show_flags(event), show_irq(event));
32293300
break;
32303301

32313302
default:
@@ -3316,11 +3387,11 @@ static void check_buffer(struct ring_buffer_per_cpu *cpu_buffer,
33163387
atomic_inc(&cpu_buffer->record_disabled);
33173388
/* There's some cases in boot up that this can happen */
33183389
WARN_ON_ONCE(system_state != SYSTEM_BOOTING);
3319-
pr_warn("[CPU: %d]TIME DOES NOT MATCH expected:%lld actual:%lld delta:%lld before:%lld after:%lld%s\n",
3390+
pr_warn("[CPU: %d]TIME DOES NOT MATCH expected:%lld actual:%lld delta:%lld before:%lld after:%lld%s context:%s\n",
33203391
cpu_buffer->cpu,
33213392
ts + info->delta, info->ts, info->delta,
33223393
info->before, info->after,
3323-
full ? " (full)" : "");
3394+
full ? " (full)" : "", show_interrupt_level());
33243395
dump_buffer_page(bpage, info, tail);
33253396
atomic_dec(&ts_dump);
33263397
/* Do not re-enable checking */

0 commit comments

Comments
 (0)