xref: /aosp_15_r20/external/mesa3d/src/freedreno/drm/freedreno_drm_perfetto.cc (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © 2024 Google, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  */
23 
24 #include <perfetto.h>
25 
26 #include "freedreno_drm_perfetto.h"
27 #include "freedreno_drmif.h"
28 
29 #include "util/log.h"
30 #include "util/perf/u_perfetto.h"
31 #include "util/simple_mtx.h"
32 
33 class FdMemoryDataSource : public perfetto::DataSource<FdMemoryDataSource> {
34  public:
OnSetup(const SetupArgs &)35    void OnSetup(const SetupArgs &) override
36    {
37    }
38 
OnStart(const StartArgs &)39    void OnStart(const StartArgs &) override
40    {
41       PERFETTO_LOG("Memory tracing started");
42    }
43 
OnStop(const StopArgs &)44    void OnStop(const StopArgs &) override
45    {
46       PERFETTO_LOG("Memory tracing stopped");
47    }
48 };
49 
50 PERFETTO_DECLARE_DATA_SOURCE_STATIC_MEMBERS(FdMemoryDataSource);
51 PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(FdMemoryDataSource);
52 
53 extern "C" void
fd_drm_perfetto_init(void)54 fd_drm_perfetto_init(void)
55 {
56    util_perfetto_init();
57 
58    perfetto::DataSourceDescriptor dsd;
59    dsd.set_name("gpu.memory.msm");
60    FdMemoryDataSource::Register(dsd);
61 }
62 
63 extern "C" void
fd_alloc_log(struct fd_bo * bo,enum fd_alloc_category from,enum fd_alloc_category to)64 fd_alloc_log(struct fd_bo *bo, enum fd_alloc_category from, enum fd_alloc_category to)
65 {
66    /* Special case for BOs that back heap chunks, they don't immediately
67     * transition to active, despite what the caller thinks:
68     */
69    if (bo->alloc_flags & _FD_BO_HINT_HEAP) {
70       if (to == FD_ALLOC_ACTIVE) {
71          to = FD_ALLOC_HEAP;
72       } else if (from == FD_ALLOC_ACTIVE) {
73          from = FD_ALLOC_HEAP;
74       }
75    }
76 
77 #define MEMORY_DEBUGGING 0
78    if (MEMORY_DEBUGGING) {
79       static simple_mtx_t lock = SIMPLE_MTX_INITIALIZER;
80 
81       assert(bo->size);
82 
83       simple_mtx_lock(&lock);
84 
85       static uint32_t sizes[4];
86       static uint32_t size_buffer, size_image, size_command, size_internal, *size_cat;
87 
88       if (from != FD_ALLOC_NONE) {
89          assert(sizes[from] >= bo->size);
90          sizes[from] -= bo->size;
91       }
92 
93       if (to != FD_ALLOC_NONE) {
94          sizes[to] += bo->size;
95       }
96 
97       if (bo->alloc_flags & FD_BO_HINT_BUFFER) {
98          size_cat = &size_buffer;
99       } else if (bo->alloc_flags & FD_BO_HINT_IMAGE) {
100          size_cat = &size_image;
101       } else if (bo->alloc_flags & FD_BO_HINT_COMMAND) {
102          size_cat = &size_command;
103       } else {
104          size_cat = &size_internal;
105       }
106       if (to == FD_ALLOC_ACTIVE) {
107          *size_cat += bo->size;
108       } else if (from == FD_ALLOC_ACTIVE) {
109          assert(*size_cat >= bo->size);
110          *size_cat -= bo->size;
111       }
112 
113       static time_t last_time;
114       struct timespec time;
115 
116       clock_gettime(CLOCK_MONOTONIC, &time);
117 
118       if (last_time != time.tv_sec) {
119          mesa_logi("active=%'u, heap=%'u, cache=%'u, buffer=%'u, image=%'u, command=%'u, internal=%'u",
120                    sizes[FD_ALLOC_ACTIVE], sizes[FD_ALLOC_HEAP], sizes[FD_ALLOC_CACHE],
121                    size_buffer, size_image, size_command, size_internal);
122          last_time = time.tv_sec;
123       }
124 
125       simple_mtx_unlock(&lock);
126    }
127 
128    if ((to != FD_ALLOC_ACTIVE) && (from != FD_ALLOC_ACTIVE))
129       return;
130 
131    FdMemoryDataSource::Trace([=](FdMemoryDataSource::TraceContext tctx) {
132       auto packet = tctx.NewTracePacket();
133 
134       packet->set_timestamp(perfetto::base::GetBootTimeNs().count());
135 
136       auto event = packet->set_vulkan_memory_event();
137 
138       event->set_timestamp(perfetto::base::GetBootTimeNs().count());
139       event->set_memory_size(bo->size);
140       event->set_memory_address(bo->iova);
141       event->set_allocation_scope(perfetto::protos::pbzero::perfetto_pbzero_enum_VulkanMemoryEvent::SCOPE_COMMAND);
142       event->set_pid(getpid());
143 
144       if (bo->alloc_flags & FD_BO_HINT_BUFFER) {
145          event->set_source(perfetto::protos::pbzero::perfetto_pbzero_enum_VulkanMemoryEvent::SOURCE_BUFFER);
146          event->set_memory_type(1);
147       } else if (bo->alloc_flags & FD_BO_HINT_IMAGE) {
148          event->set_source(perfetto::protos::pbzero::perfetto_pbzero_enum_VulkanMemoryEvent::SOURCE_IMAGE);
149          event->set_memory_type(2);
150       } else {
151          event->set_source(perfetto::protos::pbzero::perfetto_pbzero_enum_VulkanMemoryEvent::SOURCE_DRIVER);
152          event->set_memory_type(3);
153       }
154 
155       if (bo->alloc_flags & (FD_BO_HINT_BUFFER | FD_BO_HINT_IMAGE)) {
156          /* For IMAGE/BUFFER, the trace processor is looking for BIND/DESTROY_BOUND: */
157          if (to == FD_ALLOC_ACTIVE) {
158             event->set_operation(perfetto::protos::pbzero::perfetto_pbzero_enum_VulkanMemoryEvent::OP_BIND);
159          } else {
160             event->set_operation(perfetto::protos::pbzero::perfetto_pbzero_enum_VulkanMemoryEvent::OP_DESTROY_BOUND);
161          }
162       } else {
163          /* For SOURCE_DRIVER, the relevant ops are CREATE/DESTROY */
164          if (to == FD_ALLOC_ACTIVE) {
165             event->set_operation(perfetto::protos::pbzero::perfetto_pbzero_enum_VulkanMemoryEvent::OP_CREATE);
166          } else {
167             event->set_operation(perfetto::protos::pbzero::perfetto_pbzero_enum_VulkanMemoryEvent::OP_DESTROY);
168          }
169       }
170    });
171 }
172