[libcamera-devel] [PATCH v2 1/1] Use tracing with perfetto in ChromeOS

Harvey Yang chenghaoyang at chromium.org
Fri Jul 22 14:00:28 CEST 2022


As ChromeOS is using perfetto (project named as CrOSetto). When ChromeOS
uses libcamera, it should use perfetto to collect traces instead of
lttng.

Signed-off-by: Harvey Yang <chenghaoyang at chromium.org>
---
 Documentation/guides/tracing.rst              | 114 ++++++++++++++----
 include/libcamera/internal/tracepoints.h.in   |  37 +++++-
 .../internal/tracepoints/meson.build          |  25 ++--
 .../internal/tracepoints/pipeline.perfetto    |  10 ++
 .../internal/tracepoints/request.perfetto     |  30 +++++
 meson.build                                   |   7 +-
 src/android/cros/camera3_hal.cpp              |   5 +
 src/android/cros/meson.build                  |   1 +
 src/libcamera/meson.build                     |  14 ++-
 src/libcamera/pipeline_perfetto.cpp           |  24 ++++
 src/libcamera/request_perfetto.cpp            |  73 +++++++++++
 src/libcamera/tracepoints.cpp                 |  11 ++
 12 files changed, 312 insertions(+), 39 deletions(-)
 create mode 100644 include/libcamera/internal/tracepoints/pipeline.perfetto
 create mode 100644 include/libcamera/internal/tracepoints/request.perfetto
 create mode 100644 src/libcamera/pipeline_perfetto.cpp
 create mode 100644 src/libcamera/request_perfetto.cpp

diff --git a/Documentation/guides/tracing.rst b/Documentation/guides/tracing.rst
index ae960d85..53d6232e 100644
--- a/Documentation/guides/tracing.rst
+++ b/Documentation/guides/tracing.rst
@@ -16,33 +16,50 @@ at periodic points in time. This can be done with other tools such as
 callgrind, perf, gprof, etc., without modification to the application,
 and is out of scope for this guide.
 
+Library: Perfetto vs lttng-ust
+---------
+
+To integrate with CrOS tracing infrastructure, which uses perfetto (or called
+CrOSetto in CrOS), we implement the tracepoint macros (will be described below)
+with two different libraries: CrOS with perfetto, and the rest with lttng-ust.
+
 Compiling
 ---------
 
-To compile libcamera with tracing support, it must be enabled through the
-meson ``tracing`` option. It depends on the lttng-ust library (available in the
-``liblttng-ust-dev`` package for Debian-based distributions).
-By default the tracing option in meson is set to ``auto``, so if
-liblttng is detected, it will be enabled by default. Conversely, if the option
-is set to disabled, then libcamera will be compiled without tracing support.
+To compile libcamera with perfetto support in CrOS, it must be enabled through
+the meson ``tracing`` option. In CrOS, it depends on the perfetto library,
+which is by default available in CrOS; In the rest, it depends on the lttng-ust
+library (available in the ``liblttng-ust-dev`` package for Debian-based
+distributions).
+By default the tracing option in meson is set to ``auto``, so if the library is
+detected, it will be enabled by default. Conversely, if the option is set to
+disabled, then libcamera will be compiled without tracing support.
 
 Defining tracepoints
 --------------------
 
 libcamera already contains a set of tracepoints. To define additional
-tracepoints, create a file
-``include/libcamera/internal/tracepoints/{file}.tp``, where ``file`` is a
-reasonable name related to the category of tracepoints that you wish to
-define. For example, the tracepoints file for the Request object is called
-``request.tp``. An entry for this file must be added in
-``include/libcamera/internal/tracepoints/meson.build``.
-
-In this tracepoints file, define your tracepoints `as mandated by lttng
+tracepoints, create two files ``{file}.tp`` and ``{file}.perfetto``, for lttng
+and perfetto respectively, under ``include/libcamera/internal/tracepoints/``,
+and the perfetto implementation file ``src/libcamera/{file}_perfetto.cpp``,
+where ``file`` is a reasonable name related to the category of tracepoints that
+you wish to define. For example, the tracepoints files for the Request object is
+called ``request.tp`` and ``request.perfetto``. Entries for the files must be
+added in ``include/libcamera/internal/tracepoints/meson.build``.
+
+In the perfetto tracepoints files, declare the tracepoint functions in
+``{file}.perfetto``, and define them in ``{file}_perfetto.cpp``, `as mandated
+by perfetto <https://perfetto.dev/docs/instrumentation/track-events>`_.
+Currently the only enabled perfetto::Category is ``libcamera``. If you intend to
+use another category, remember to define it in
+``include/libcamera/internal/tracepoints.h.in``, and enable it when collecting
+traces.
+
+In the lttng tracepoints file, define your tracepoints `as mandated by lttng
 <https://lttng.org/man/3/lttng-ust>`_. The header boilerplate must *not* be
 included (as it will conflict with the rest of our infrastructure), and
 only the tracepoint definitions (with the ``TRACEPOINT_*`` macros) should be
 included.
-
 All tracepoint providers shall be ``libcamera``. According to lttng, the
 tracepoint provider should be per-project; this is the rationale for this
 decision. To group tracepoint events, we recommend using
@@ -68,9 +85,9 @@ Then to use the tracepoint:
 
 ``LIBCAMERA_TRACEPOINT({tracepoint_event}, args...)``
 
-This macro must be used, as opposed to lttng's macros directly, because
-lttng is an optional dependency of libcamera, so the code must compile and run
-even when lttng is not present or when tracing is disabled.
+This macro must be used, as opposed to perfetto's/lttng's macros directly,
+because tracing support is optional of libcamera, so the code must compile and
+run even when perfetto/lttng is not present or when tracing is disabled.
 
 The tracepoint provider name, as declared in the tracepoint definition, is not
 included in the parameters of the tracepoint.
@@ -86,7 +103,7 @@ and when the pipeline handler receives the corresponding response from the IPA,
 respectively. These are the tracepoints that our sample analysis script
 (see "Analyzing a trace") scans for when computing statistics on IPA call time.
 
-Using tracepoints (from an application)
+Using lttng tracepoints (from an application)
 ---------------------------------------
 
 As applications are not part of libcamera, but rather users of libcamera,
@@ -94,13 +111,66 @@ applications should seek their own tracing mechanisms. For ease of tracing
 the application alongside tracing libcamera, it is recommended to also
 `use lttng <https://lttng.org/docs/#doc-tracing-your-own-user-application>`_.
 
-Using tracepoints (from closed-source IPA)
+Using lttng tracepoints (from closed-source IPA)
 ------------------------------------------
 
 Similar to applications, closed-source IPAs can simply use lttng on their own,
 or any other tracing mechanism if desired.
 
-Collecting a trace
+Collecting a perfetto trace
+------------------
+
+A trace can be collected with the following steps:
+
+1. Start `traced` if it hasn't been started.
+.. code-block:: bash
+
+   start traced
+
+2. Start a consumer that includes “track_event” data source in the trace
+   config, and “libcamera” category.
+.. code-block:: bash
+
+   perfetto -c - --txt -o /tmp/perfetto-trace \
+   <<EOF
+
+   buffers: {
+       size_kb: 63488
+       fill_policy: DISCARD
+   }
+   buffers: {
+       size_kb: 2048
+       fill_policy: DISCARD
+   }
+   data_sources: {
+        config {
+            name: "track_event"
+            track_event_config {
+                enabled_categories: "libcamera"
+            }
+        }
+   }
+   duration_ms: 10000
+
+   EOF
+
+3. Execute the libcamera behavior you intend to trace during the set duration
+   (10000 ms) in the above example.
+
+4. After the consumer (cmd `perfetto`) is done, you can find the trace result
+   in ``/tmp/perfetto-trace``.
+
+Analyzing a perfetto trace
+-----------------
+
+Follow the `guide <https://perfetto.dev/docs/visualization/perfetto-ui>`_ to
+visualize the trace.
+
+In other words, upload the trace to `Perfetto UI <https://ui.perfetto.dev/>`_,
+where you can check the timeline of tracepoints on each process/thread. You can
+also run SQL queries to do analysis.
+
+Collecting a lttng trace
 ------------------
 
 A trace can be collected fairly simply from lttng:
@@ -123,7 +193,7 @@ viewed by: ``lttng view -t $PATH_TO_TRACE``, where ``$PATH_TO_TRACE`` is the
 path that was printed when the session was created. This is the same path that
 is used when analyzing traces programatically, as described in the next section.
 
-Analyzing a trace
+Analyzing a lttng trace
 -----------------
 
 As mentioned above, while an lttng tracing session exists and the trace is not
diff --git a/include/libcamera/internal/tracepoints.h.in b/include/libcamera/internal/tracepoints.h.in
index d0fc1365..d91fadd7 100644
--- a/include/libcamera/internal/tracepoints.h.in
+++ b/include/libcamera/internal/tracepoints.h.in
@@ -9,7 +9,24 @@
 #ifndef __LIBCAMERA_INTERNAL_TRACEPOINTS_H__
 #define __LIBCAMERA_INTERNAL_TRACEPOINTS_H__
 
-#if HAVE_TRACING
+#if HAVE_PERFETTO
+
+#include <perfetto/perfetto.h>
+
+PERFETTO_DEFINE_CATEGORIES(
+	perfetto::Category("libcamera")
+		.SetDescription("Events from libcamera"));
+
+#define LIBCAMERA_TRACEPOINT(t_name, ...) \
+LIBCAMERA_TRACE_EVENT_##t_name(__VA_ARGS__)
+
+#define LIBCAMERA_TRACEPOINT_IPA_BEGIN(pipe, func) \
+LIBCAMERA_TRACE_EVENT_ipa_call_begin(#pipe, #func)
+
+#define LIBCAMERA_TRACEPOINT_IPA_END(pipe, func) \
+LIBCAMERA_TRACE_EVENT_ipa_call_end(#pipe, #func)
+
+#elif HAVE_TRACING /* !HAVE_PERFETTO */
 #define LIBCAMERA_TRACEPOINT(...) tracepoint(libcamera, __VA_ARGS__)
 
 #define LIBCAMERA_TRACEPOINT_IPA_BEGIN(pipe, func) \
@@ -18,7 +35,7 @@ tracepoint(libcamera, ipa_call_begin, #pipe, #func)
 #define LIBCAMERA_TRACEPOINT_IPA_END(pipe, func) \
 tracepoint(libcamera, ipa_call_end, #pipe, #func)
 
-#else
+#else /* HAVE_PERFETTO */
 
 namespace {
 
@@ -34,12 +51,15 @@ inline void unused([[maybe_unused]] Args&& ...args)
 #define LIBCAMERA_TRACEPOINT_IPA_BEGIN(pipe, func)
 #define LIBCAMERA_TRACEPOINT_IPA_END(pipe, func)
 
-#endif /* HAVE_TRACING */
+#endif /* HAVE_PERFETTO */
 
 #endif /* __LIBCAMERA_INTERNAL_TRACEPOINTS_H__ */
 
+#if HAVE_PERFETTO
+
+#include <perfetto/perfetto.h>
 
-#if HAVE_TRACING
+#elif HAVE_TRACING
 
 #undef TRACEPOINT_PROVIDER
 #define TRACEPOINT_PROVIDER libcamera
@@ -52,10 +72,15 @@ inline void unused([[maybe_unused]] Args&& ...args)
 
 #include <lttng/tracepoint.h>
 
-{{source}}
 
 #endif /* INCLUDE_LIBCAMERA_INTERNAL_TRACEPOINTS_TP_H */
 
 #include <lttng/tracepoint-event.h>
 
-#endif /* HAVE_TRACING */
+#endif /* HAVE_PERFETTO */
+
+#if HAVE_PERFETTO || HAVE_TRACING
+
+{{source}}
+
+#endif /* HAVE_PERFETTO || HAVE_TRACING */
diff --git a/include/libcamera/internal/tracepoints/meson.build b/include/libcamera/internal/tracepoints/meson.build
index d9b2fca5..ff5aece6 100644
--- a/include/libcamera/internal/tracepoints/meson.build
+++ b/include/libcamera/internal/tracepoints/meson.build
@@ -1,12 +1,19 @@
 # SPDX-License-Identifier: CC0-1.0
 
-# enum files must go first
-tracepoint_files = files([
-    'buffer_enums.tp',
-    'request_enums.tp',
-])
+if get_option('android').enabled() and get_option('android_platform') == 'cros'
+  tracepoint_files = files([
+      'pipeline.perfetto',
+      'request.perfetto',
+  ])
+else
+  # enum files must go first
+  tracepoint_files = files([
+      'buffer_enums.tp',
+      'request_enums.tp',
+  ])
 
-tracepoint_files += files([
-    'pipeline.tp',
-    'request.tp',
-])
+  tracepoint_files += files([
+      'pipeline.tp',
+      'request.tp',
+  ])
+endif
diff --git a/include/libcamera/internal/tracepoints/pipeline.perfetto b/include/libcamera/internal/tracepoints/pipeline.perfetto
new file mode 100644
index 00000000..5f45295e
--- /dev/null
+++ b/include/libcamera/internal/tracepoints/pipeline.perfetto
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2022, Google Inc.
+ *
+ * pipeline.tp - Tracepoints for pipelines
+ */
+
+void LIBCAMERA_TRACE_EVENT_ipa_call_begin(const char *pipe, const char *func);
+
+void LIBCAMERA_TRACE_EVENT_ipa_call_end(const char *pipe, const char *func);
diff --git a/include/libcamera/internal/tracepoints/request.perfetto b/include/libcamera/internal/tracepoints/request.perfetto
new file mode 100644
index 00000000..fd6a42a4
--- /dev/null
+++ b/include/libcamera/internal/tracepoints/request.perfetto
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2022, Google Inc.
+ *
+ * request.tp - Tracepoints for the request object
+ */
+
+#include <libcamera/internal/request.h>
+
+#include <libcamera/framebuffer.h>
+
+void LIBCAMERA_TRACE_EVENT_request(libcamera::Request *req);
+
+void LIBCAMERA_TRACE_EVENT_request_construct(libcamera::Request *req);
+
+void LIBCAMERA_TRACE_EVENT_request_destroy(libcamera::Request *req);
+
+void LIBCAMERA_TRACE_EVENT_request_reuse(libcamera::Request *req);
+
+void LIBCAMERA_TRACE_EVENT_request_queue(libcamera::Request *req);
+
+void LIBCAMERA_TRACE_EVENT_request_device_queue(libcamera::Request *req);
+
+void LIBCAMERA_TRACE_EVENT_request_complete(libcamera::Request::Private *req);
+
+void LIBCAMERA_TRACE_EVENT_request_cancel(libcamera::Request::Private *req);
+
+void LIBCAMERA_TRACE_EVENT_request_complete_buffer(
+		libcamera::Request::Private *req,
+		libcamera::FrameBuffer * buf);
diff --git a/meson.build b/meson.build
index 29d8542d..434540e1 100644
--- a/meson.build
+++ b/meson.build
@@ -125,7 +125,11 @@ libcamera_includes = include_directories('include')
 py_modules = []
 
 # Libraries used by multiple components
-liblttng = cc.find_library('lttng-ust', required : get_option('tracing'))
+libperfetto = dependency('perfetto', required : get_option('tracing').enabled()
+    and get_option('android').enabled()
+    and get_option('android_platform') == 'cros')
+liblttng = cc.find_library('lttng-ust', required : get_option('tracing').enabled()
+    and not libperfetto.found())
 
 # Pipeline handlers
 #
@@ -176,6 +180,7 @@ py_mod.find_installation('python3', modules: py_modules)
 summary({
             'Enabled pipelines': pipelines,
             'Enabled IPA modules': ipa_modules,
+            'Perfetto support': perfetto_enabled,
             'Tracing support': tracing_enabled,
             'Android support': android_enabled,
             'GStreamer support': gst_enabled,
diff --git a/src/android/cros/camera3_hal.cpp b/src/android/cros/camera3_hal.cpp
index fb863b5f..2fbd7f14 100644
--- a/src/android/cros/camera3_hal.cpp
+++ b/src/android/cros/camera3_hal.cpp
@@ -7,10 +7,15 @@
 
 #include <cros-camera/cros_camera_hal.h>
 
+#include "libcamera/internal/tracepoints.h"
 #include "../camera_hal_manager.h"
 
 static void set_up([[maybe_unused]] cros::CameraMojoChannelManagerToken *token)
 {
+	perfetto::TracingInitArgs args;
+	args.backends |= perfetto::kSystemBackend;
+	perfetto::Tracing::Initialize(args);
+	perfetto::TrackEvent::Register();
 }
 
 static void tear_down()
diff --git a/src/android/cros/meson.build b/src/android/cros/meson.build
index 35995dd8..68f2bd9e 100644
--- a/src/android/cros/meson.build
+++ b/src/android/cros/meson.build
@@ -9,5 +9,6 @@ android_hal_sources += files([
 ])
 
 android_deps += dependency('libcros_camera')
+android_deps += dependency('perfetto')
 
 android_cpp_args += ['-DOS_CHROMEOS']
diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
index 26912ca1..39a55a17 100644
--- a/src/libcamera/meson.build
+++ b/src/libcamera/meson.build
@@ -71,11 +71,22 @@ if libgnutls.found()
     config_h.set('HAVE_GNUTLS', 1)
 endif
 
-if liblttng.found()
+if libperfetto.found()
+    perfetto_enabled = true
+    tracing_enabled = false
+    config_h.set('HAVE_PERFETTO', 1)
+    libcamera_sources += [
+        'pipeline_perfetto.cpp',
+        'request_perfetto.cpp',
+        'tracepoints.cpp',
+    ]
+elif liblttng.found()
+    perfetto_enabled = false
     tracing_enabled = true
     config_h.set('HAVE_TRACING', 1)
     libcamera_sources += files(['tracepoints.cpp'])
 else
+    perfetto_enabled = false
     tracing_enabled = false
 endif
 
@@ -125,6 +136,7 @@ libcamera_deps = [
     libdl,
     libgnutls,
     liblttng,
+    libperfetto,
     libudev,
 ]
 
diff --git a/src/libcamera/pipeline_perfetto.cpp b/src/libcamera/pipeline_perfetto.cpp
new file mode 100644
index 00000000..07b82ffd
--- /dev/null
+++ b/src/libcamera/pipeline_perfetto.cpp
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2022, Google Inc.
+ *
+ * pipeline.tp - Tracepoints for pipelines
+ */
+
+#include "libcamera/internal/tracepoints.h"
+
+void LIBCAMERA_TRACE_EVENT_ipa_call_begin(const char *pipe, const char *func)
+{
+	// TODO: Consider TRACE_EVENT_BEGIN
+	TRACE_EVENT("libcamera", "ipa_call_begin",
+		    "pipeline_name", pipe,
+		    "function_name", func);
+}
+
+void LIBCAMERA_TRACE_EVENT_ipa_call_end(const char *pipe, const char *func)
+{
+	// TODO: Consider TRACE_EVENT_END
+	TRACE_EVENT("libcamera", "ipa_call_end",
+		    "pipeline_name", pipe,
+		    "function_name", func);
+}
diff --git a/src/libcamera/request_perfetto.cpp b/src/libcamera/request_perfetto.cpp
new file mode 100644
index 00000000..2cfff28e
--- /dev/null
+++ b/src/libcamera/request_perfetto.cpp
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2022, Google Inc.
+ *
+ * request.tp - Tracepoints for the request object
+ */
+
+#include <libcamera/framebuffer.h>
+
+#include "libcamera/internal/request.h"
+#include "libcamera/internal/tracepoints.h"
+
+void LIBCAMERA_TRACE_EVENT_request(libcamera::Request *req)
+{
+	TRACE_EVENT("libcamera", "request",
+		    "request_ptr", reinterpret_cast<uintptr_t>(req),
+		    "cookie", req->cookie(),
+		    "status", req->status()); // TODO
+}
+
+void LIBCAMERA_TRACE_EVENT_request_construct(libcamera::Request *req)
+{
+	TRACE_EVENT("libcamera", "request_construct",
+		    "request_ptr", reinterpret_cast<uintptr_t>(req));
+}
+
+void LIBCAMERA_TRACE_EVENT_request_destroy(libcamera::Request *req)
+{
+	TRACE_EVENT("libcamera", "request_destroy",
+		    "request_ptr", reinterpret_cast<uintptr_t>(req));
+}
+
+void LIBCAMERA_TRACE_EVENT_request_reuse(libcamera::Request *req)
+{
+	TRACE_EVENT("libcamera", "request_reuse",
+		    "request_ptr", reinterpret_cast<uintptr_t>(req));
+}
+
+void LIBCAMERA_TRACE_EVENT_request_queue(libcamera::Request *req)
+{
+	TRACE_EVENT("libcamera", "request_queue",
+		    "request_ptr", reinterpret_cast<uintptr_t>(req));
+}
+
+void LIBCAMERA_TRACE_EVENT_request_device_queue(libcamera::Request *req)
+{
+	TRACE_EVENT("libcamera", "request_device_queue",
+		    "request_ptr", reinterpret_cast<uintptr_t>(req));
+}
+
+void LIBCAMERA_TRACE_EVENT_request_complete(libcamera::Request::Private *req)
+{
+	TRACE_EVENT("libcamera", "request_complete",
+		    "request_private_ptr", reinterpret_cast<uintptr_t>(req));
+}
+
+void LIBCAMERA_TRACE_EVENT_request_cancel(libcamera::Request::Private *req)
+{
+	TRACE_EVENT("libcamera", "request_cancel",
+		    "request_private_ptr", reinterpret_cast<uintptr_t>(req));
+}
+
+void LIBCAMERA_TRACE_EVENT_request_complete_buffer(
+	libcamera::Request::Private *req,
+	libcamera::FrameBuffer *buf)
+{
+	TRACE_EVENT("libcamera", "request_complete_buffer",
+		    "request_private_ptr", reinterpret_cast<uintptr_t>(req),
+		    "cookie", req->_o<libcamera::Request>()->cookie(),
+		    "status", req->_o<libcamera::Request>()->status(), // TODO
+		    "buffer_ptr", reinterpret_cast<uintptr_t>(buf),
+		    "buffer_status", buf->metadata().status); // TODO
+}
diff --git a/src/libcamera/tracepoints.cpp b/src/libcamera/tracepoints.cpp
index 0173b75a..a07ea531 100644
--- a/src/libcamera/tracepoints.cpp
+++ b/src/libcamera/tracepoints.cpp
@@ -4,7 +4,18 @@
  *
  * tracepoints.cpp - Tracepoints with lttng
  */
+
+#if HAVE_PERFETTO
+
+#include "libcamera/internal/tracepoints.h"
+
+PERFETTO_TRACK_EVENT_STATIC_STORAGE();
+
+#else
+
 #define TRACEPOINT_CREATE_PROBES
 #define TRACEPOINT_DEFINE
 
 #include "libcamera/internal/tracepoints.h"
+
+#endif /* HAVE_PERFETTO */
-- 
2.37.1.359.gd136c6c3e2-goog



More information about the libcamera-devel mailing list