Module: Mesa
Branch: main
Commit: a34fcaf326f871e5136030aa23e2cf81d85b587b
URL:    
http://cgit.freedesktop.org/mesa/mesa/commit/?id=a34fcaf326f871e5136030aa23e2cf81d85b587b

Author: Lionel Landwerlin <[email protected]>
Date:   Thu Jan 12 01:08:46 2023 +0200

util/u_trace: add support for variable length trace points

Use case being :

struct tp {
   ...
   char string[0];
};

Signed-off-by: Lionel Landwerlin <[email protected]>
Reviewed-by: Emma Anholt <[email protected]>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/16655>

---

 src/util/perf/u_trace.c      | 14 ++++++++------
 src/util/perf/u_trace.py     | 28 ++++++++++++++++++++++++++--
 src/util/perf/u_trace_priv.h | 20 +++++++++++++++++---
 3 files changed, 51 insertions(+), 11 deletions(-)

diff --git a/src/util/perf/u_trace.c b/src/util/perf/u_trace.c
index b353f1984e6..c57631e3d0f 100644
--- a/src/util/perf/u_trace.c
+++ b/src/util/perf/u_trace.c
@@ -801,18 +801,20 @@ u_trace_disable_event_range(struct u_trace_iterator 
begin_it,
  * functions.
  */
 void *
-u_trace_append(struct u_trace *ut, void *cs, const struct u_tracepoint *tp)
+u_trace_appendv(struct u_trace *ut, void *cs,
+                const struct u_tracepoint *tp, unsigned variable_sz)
 {
-   struct u_trace_chunk *chunk = get_chunk(ut, tp->payload_sz);
-   unsigned tp_idx = chunk->num_traces++;
-
    assert(tp->payload_sz == ALIGN_NPOT(tp->payload_sz, 8));
 
+   unsigned payload_sz = ALIGN_NPOT(tp->payload_sz + variable_sz, 8);
+   struct u_trace_chunk *chunk = get_chunk(ut, payload_sz);
+   unsigned tp_idx = chunk->num_traces++;
+
    /* sub-allocate storage for trace payload: */
    void *payload = NULL;
-   if (tp->payload_sz > 0) {
+   if (payload_sz > 0) {
       payload = chunk->payload->next;
-      chunk->payload->next += tp->payload_sz;
+      chunk->payload->next += payload_sz;
    }
 
    /* record a timestamp for the trace: */
diff --git a/src/util/perf/u_trace.py b/src/util/perf/u_trace.py
index 521723249da..3ca639752be 100644
--- a/src/util/perf/u_trace.py
+++ b/src/util/perf/u_trace.py
@@ -53,11 +53,17 @@ class Tracepoint(object):
         assert isinstance(args, list)
         assert name not in TRACEPOINTS
 
+
         self.name = name
         self.args = args
         if tp_struct is None:
            tp_struct = args
         self.tp_struct = tp_struct
+        self.has_variable_arg = False
+        for arg in self.tp_struct:
+            if arg.length_arg != None:
+                self.has_variable_arg = True
+                break
         self.tp_print = tp_print
         self.tp_perfetto = tp_perfetto
         self.tp_markers = tp_markers
@@ -97,7 +103,7 @@ class TracepointArgStruct():
 class TracepointArg(object):
     """Class that represents either an argument being passed or a field in a 
struct
     """
-    def __init__(self, type, var, c_format, name=None, to_prim_type=None):
+    def __init__(self, type, var, c_format, name=None, to_prim_type=None, 
length_arg=None, copy_func=None):
         """Parameters:
 
         - type: argument's C type.
@@ -107,6 +113,7 @@ class TracepointArg(object):
           be displayed in output or perfetto, otherwise var will be used.
         - to_prim_type: (optional) C function to convert from arg's type to a 
type
           compatible with c_format.
+        - length_arg: whether this argument is a variable length array
         """
         assert isinstance(type, str)
         assert isinstance(var, str)
@@ -119,6 +126,8 @@ class TracepointArg(object):
            name = var
         self.name = name
         self.to_prim_type = to_prim_type
+        self.length_arg = length_arg
+        self.copy_func = copy_func
 
 
 HEADERS = []
@@ -215,7 +224,7 @@ void ${trace_toggle_name}_config_variable(void);
  */
 struct trace_${trace_name} {
 %    for arg in trace.tp_struct:
-   ${arg.type} ${arg.name};
+   ${arg.type} ${arg.name}${"[0]" if arg.length_arg else ""};
 %    endfor
 %    if len(trace.args) == 0:
 #ifdef __cplusplus
@@ -455,10 +464,25 @@ void __trace_${trace_name}(
    struct trace_${trace_name} entry;
    UNUSED struct trace_${trace_name} *__entry =
       enabled_traces & U_TRACE_TYPE_REQUIRE_QUEUING ?
+ % if trace.has_variable_arg:
+      (struct trace_${trace_name} *)u_trace_appendv(ut, ${cs_param_value + 
","} &__tp_${trace_name},
+                                                    0
+  % for arg in trace.tp_struct:
+   % if arg.length_arg is not None:
+                                                    + ${arg.length_arg}
+   % endif
+  % endfor
+                                                    ) :
+ % else:
       (struct trace_${trace_name} *)u_trace_append(ut, ${cs_param_value + ","} 
&__tp_${trace_name}) :
+ % endif
       &entry;
  % for arg in trace.tp_struct:
+  % if arg.length_arg is None:
    __entry->${arg.name} = ${arg.var};
+  % else:
+   ${arg.copy_func}(__entry->${arg.name}, ${arg.var}, ${arg.length_arg});
+  % endif
  % endfor
  % if trace.tp_markers is not None:
    if (enabled_traces & U_TRACE_TYPE_MARKERS)
diff --git a/src/util/perf/u_trace_priv.h b/src/util/perf/u_trace_priv.h
index d925b06526b..9804fa31f73 100644
--- a/src/util/perf/u_trace_priv.h
+++ b/src/util/perf/u_trace_priv.h
@@ -54,9 +54,23 @@ struct u_tracepoint {
 };
 
 /**
- * Append a tracepoint, returning pointer that can be filled with trace
- * payload.
+ * Append a tracepoint followed by some amount of memory specified by
+ * variable_sz, returning pointer that can be filled with trace payload.
  */
-void * u_trace_append(struct u_trace *ut, void *cs, const struct u_tracepoint 
*tp);
+void * u_trace_appendv(struct u_trace *ut, void *cs,
+                       const struct u_tracepoint *tp, unsigned variable_sz);
+
+/**
+ * Append a trace event, returning pointer to buffer of tp->payload_sz
+ * to be filled in with trace payload.  Called by generated tracepoint
+ * functions.
+ */
+static inline void *
+u_trace_append(struct u_trace *ut, void *cs, const struct u_tracepoint *tp)
+{
+   return u_trace_appendv(ut, cs, tp, 0);
+}
+
+
 
 #endif  /* _U_TRACE_PRIV_H */

Reply via email to