@@ -176,6 +176,15 @@ Printer
.. kernel-doc:: drivers/gpu/drm/drm_print.c
:export:
+Tracing
+-------
+
+.. kernel-doc:: drivers/gpu/drm/drm_trace.h
+ :doc: overview
+
+.. kernel-doc:: drivers/gpu/drm/drm_trace.h
+ :internal:
+
Utilities
---------
@@ -7,21 +7,109 @@
#include <linux/tracepoint.h>
struct drm_file;
+/**
+ * DOC: overview
+ *
+ * DRM trace events can be used to trace important moments occurring in the DRM
+ * core or helpers without incurring a significant performance penalty (like you
+ * would with console logging).
+ */
+
+#if !defined(_DRM_TRACE_EVENT_CLASS_ENUM)
+#define _DRM_TRACE_EVENT_CLASS_ENUM
+
+/**
+ * enum drm_trace_event_class - the trace class of an event
+ *
+ * Trace events are broken into different classes (much the same as we do for
+ * console logging) to make sifting through the logs easier. If you want to
+ * isolate one or more classes (or disable a subset of classes), you can write
+ * an expession using the event_class entry field as a tracepoints filter. The
+ * event_class field is not printed as part of the trace log, it's just there
+ * for filtering.
+ *
+ * The classes are bitfields to make filtering easier, but also to allow trace
+ * events to be classified under multiple classes (ie: if you're tracing an
+ * error that occurred with a crtc, you can ensure that these events are
+ * surfaced for filters looking for either crtc or error classes).
+ *
+ * An example filter is:
+ * Assume you want to view all trace events in failure paths, you would
+ * write a filter which isolates events with the drm_trace_class_error bit
+ * set in their event_class field. This allows you to enable all trace
+ * events in the drm trace system and only consume errors.
+ *
+ * ; echo "event_class & 0x1" > /sys/kernel/tracing/events/drm/filter
+ * ; echo 1 > /sys/kernel/tracing/events/drm/enable
+ *
+ * Similarly, to view all vblank traces plus any error traces, you select
+ * both classes in the filter.
+ *
+ * ; echo "event_class & 0x3" > /sys/kernel/tracing/events/drm/filter
+ */
+enum drm_trace_event_class {
+ /**
+ * @drm_trace_class_error: Denotes that the trace event is coming from
+ * an error path.
+ */
+ drm_trace_class_error = BIT(0),
+
+ /**
+ * @drm_trace_class_vblank: Use this to track trace events that track
+ * vblanks and vblank events.
+ */
+ drm_trace_class_vblank = BIT(1),
+};
+
+/**
+ * drm_trace - add a drm trace event
+ * @_c: class name (the part that comes after drm_trace_class_)
+ * @_e: event name (the part that comes after drm_$class_)
+ *
+ * Use this macro to simplify adding a trace event for non-failure paths in
+ * drm code. The macro simply assembles the trace event from the class and name,
+ * and sets the correct event_code for this trace.
+ *
+ * It's recommended that this macro is not used in failure paths. For failure
+ * paths, use drm_trace_err().
+ */
+#define drm_trace(_c, _e, ...) \
+ trace_drm_##_c##_##_e(drm_trace_class_##_c, __VA_ARGS__)
+
+/**
+ * drm_trace_err - add a drm trace event in a failure path
+ * @_c: class name (the part that comes after drm_trace_class_)
+ * @_e: event name (the part that comes after drm_$class_)
+ *
+ * This is virtually the same as drm_trace(), however it sets the error class on
+ * the event as well. This is beneficial for those filtering events by
+ * class_error.
+ *
+ * For non-failure paths, please use drm_trace().
+ */
+#define drm_trace_err(_c, _e, ...) \
+ trace_drm_##_c##_##_e(drm_trace_class_##_c | drm_trace_class_error, \
+ __VA_ARGS__)
+
+#endif
#undef TRACE_SYSTEM
#define TRACE_SYSTEM drm
#define TRACE_INCLUDE_FILE drm_trace
TRACE_EVENT(drm_vblank_event,
- TP_PROTO(int crtc, unsigned int seq, ktime_t time, bool high_prec),
- TP_ARGS(crtc, seq, time, high_prec),
+ TP_PROTO(unsigned int event_class, int crtc, unsigned int seq,
+ ktime_t time, bool high_prec),
+ TP_ARGS(event_class, crtc, seq, time, high_prec),
TP_STRUCT__entry(
+ __field(unsigned int, event_class)
__field(int, crtc)
__field(unsigned int, seq)
__field(ktime_t, time)
__field(bool, high_prec)
),
TP_fast_assign(
+ __entry->event_class = event_class;
__entry->crtc = crtc;
__entry->seq = seq;
__entry->time = time;
@@ -33,14 +121,17 @@ TRACE_EVENT(drm_vblank_event,
);
DECLARE_EVENT_CLASS(class_drm_vblank_event,
- TP_PROTO(struct drm_file *file, int crtc, unsigned int seq),
- TP_ARGS(file, crtc, seq),
+ TP_PROTO(unsigned int event_class, struct drm_file *file,
+ int crtc, unsigned int seq),
+ TP_ARGS(event_class, file, crtc, seq),
TP_STRUCT__entry(
+ __field(unsigned int, event_class)
__field(struct drm_file *, file)
__field(int, crtc)
__field(unsigned int, seq)
),
TP_fast_assign(
+ __entry->event_class = event_class;
__entry->file = file;
__entry->crtc = crtc;
__entry->seq = seq;
@@ -49,12 +140,14 @@ DECLARE_EVENT_CLASS(class_drm_vblank_event,
__entry->seq)
);
DEFINE_EVENT(class_drm_vblank_event, drm_vblank_event_queued,
- TP_PROTO(struct drm_file *file, int crtc, unsigned int seq),
- TP_ARGS(file, crtc, seq)
+ TP_PROTO(unsigned int event_class, struct drm_file *file, int crtc,
+ unsigned int seq),
+ TP_ARGS(event_class, file, crtc, seq)
);
DEFINE_EVENT(class_drm_vblank_event, drm_vblank_event_delivered,
- TP_PROTO(struct drm_file *file, int crtc, unsigned int seq),
- TP_ARGS(file, crtc, seq)
+ TP_PROTO(unsigned int event_class, struct drm_file *file, int crtc,
+ unsigned int seq),
+ TP_ARGS(event_class, file, crtc, seq)
);
#endif /* _DRM_TRACE_H_ */
@@ -880,7 +880,7 @@ static void send_vblank_event(struct drm_device *dev,
e->event.seq.time_ns = ktime_to_ns(now);
break;
}
- trace_drm_vblank_event_delivered(e->base.file_priv, e->pipe, seq);
+ drm_trace(vblank, event_delivered, e->base.file_priv, e->pipe, seq);
drm_send_event_locked(dev, &e->base);
}
@@ -1529,7 +1529,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe,
DRM_DEBUG("event on vblank count %llu, current %llu, crtc %u\n",
req_seq, seq, pipe);
- trace_drm_vblank_event_queued(file_priv, pipe, req_seq);
+ drm_trace(vblank, event_queued, file_priv, pipe, req_seq);
e->sequence = req_seq;
if (vblank_passed(seq, req_seq)) {
@@ -1760,8 +1760,8 @@ static void drm_handle_vblank_events(struct drm_device *dev, unsigned int pipe)
send_vblank_event(dev, e, seq, now);
}
- trace_drm_vblank_event(pipe, seq, now,
- dev->driver->get_vblank_timestamp != NULL);
+ drm_trace(vblank, event, pipe, seq, now,
+ dev->driver->get_vblank_timestamp != NULL);
}
/**