1 /*
2 * Copyright © 2024 Raspberry Pi Ltd
3 * SPDX-License-Identifier: MIT
4 */
5
6 #include "v3d_pps_driver.h"
7
8 #include <perfetto.h>
9 #include <string.h>
10 #include <string>
11
12 #include "perfcntrs/v3d_perfcntrs.h"
13 #include <xf86drm.h>
14
15 namespace pps
16 {
17
18 uint64_t
get_min_sampling_period_ns()19 V3DDriver::get_min_sampling_period_ns()
20 {
21 return 100000;
22 }
23
24 bool
init_perfcnt()25 V3DDriver::init_perfcnt()
26 {
27 const char *v3d_ds_counter_env = getenv("V3D_DS_COUNTER");
28 if (!v3d_ds_counter_env || v3d_ds_counter_env[0] == '\0')
29 return false;
30
31 bool success = v3d_get_device_info(drm_device.fd, &devinfo, &drmIoctl);
32 if (!success)
33 return false;
34
35 perfcntrs = v3d_perfcntrs_init(&devinfo, drm_device.fd);
36 if (!perfcntrs)
37 return false;
38
39 groups.clear();
40 counters.clear();
41 enabled_counters.clear();
42
43 struct drm_v3d_perfmon_create createreq = { 0 };
44 CounterGroup group = {};
45
46 char *dup = strdup(v3d_ds_counter_env);
47 char *name = strtok(dup, ",");
48 while (name != NULL && createreq.ncounters < DRM_V3D_MAX_PERF_COUNTERS) {
49 const struct v3d_perfcntr_desc *desc = v3d_perfcntrs_get_by_name(perfcntrs, name);
50 if (desc) {
51 Counter counter_desc = {};
52
53 counter_desc.units = Counter::Units::None;
54 counter_desc.id = createreq.ncounters;
55 counter_desc.name = desc->name;
56 counter_desc.group = group.id;
57 counter_desc.getter = [this](
58 const Counter &c, const Driver &dri) -> Counter::Value {
59 return static_cast<int64_t>(values[c.id]);
60 };
61
62 counters.emplace_back(std::move(counter_desc));
63 createreq.counters[createreq.ncounters++] = desc->index;
64 } else {
65 PERFETTO_ELOG("Unkown performance counter name: %s", name);
66 }
67
68 name = strtok(NULL, ",");
69 }
70
71 free(dup);
72
73 if (createreq.ncounters == 0)
74 return false;
75
76 int ret = drmIoctl(drm_device.fd, DRM_IOCTL_V3D_PERFMON_CREATE, &createreq);
77 if (ret != 0)
78 PERFETTO_FATAL("Failed to create perfmon %s", strerror(errno));
79
80 perfmon_id = createreq.id;
81
82 return true;
83 }
84
85 void
enable_counter(uint32_t counter_id)86 V3DDriver::enable_counter(uint32_t counter_id)
87 {
88 enabled_counters.push_back(counters[counter_id]);
89 }
90
91 void
enable_all_counters()92 V3DDriver::enable_all_counters()
93 {
94 enabled_counters.reserve(counters.size());
95 enabled_counters.insert(enabled_counters.end(), counters.begin(), counters.end());
96 }
97
98 void
enable_perfcnt(uint64_t sampling_period_ns)99 V3DDriver::enable_perfcnt(uint64_t sampling_period_ns)
100 {
101 struct drm_v3d_perfmon_set_global globalreq = {
102 .id = perfmon_id,
103 };
104
105 int ret = drmIoctl(drm_device.fd, DRM_IOCTL_V3D_PERFMON_SET_GLOBAL, &globalreq);
106 if (ret != 0) {
107 if (errno == ENOTTY)
108 PERFETTO_FATAL("Failed to set global perfmon. Feature not available - update your kernel");
109 else
110 PERFETTO_FATAL("Failed to set global perfmon %s", strerror(errno));
111 }
112 }
113
114 void
disable_perfcnt()115 V3DDriver::disable_perfcnt()
116 {
117 struct drm_v3d_perfmon_set_global globalreq = {
118 .flags = DRM_V3D_PERFMON_CLEAR_GLOBAL,
119 .id = perfmon_id,
120 };
121
122 int ret = drmIoctl(drm_device.fd, DRM_IOCTL_V3D_PERFMON_SET_GLOBAL, &globalreq);
123 if (ret != 0)
124 PERFETTO_FATAL("Failed to clear global perfmon %s", strerror(errno));
125
126 struct drm_v3d_perfmon_destroy destroyreq = {
127 .id = perfmon_id,
128 };
129
130 ret = drmIoctl(drm_device.fd, DRM_IOCTL_V3D_PERFMON_DESTROY, &destroyreq);
131 if (ret != 0)
132 PERFETTO_FATAL("Failed to destroy perfmon %s", strerror(errno));
133 }
134
135 bool
dump_perfcnt()136 V3DDriver::dump_perfcnt()
137 {
138 last_dump_ts = perfetto::base::GetBootTimeNs().count();
139
140 struct drm_v3d_perfmon_get_values req = {
141 .id = perfmon_id,
142 .values_ptr = (uintptr_t)values,
143 };
144
145 int ret = drmIoctl(drm_device.fd, DRM_IOCTL_V3D_PERFMON_GET_VALUES, &req);
146 if (ret != 0) {
147 PERFETTO_FATAL("Can't request perfmon counters values\n");
148 return false;
149 }
150
151 return true;
152 }
153
154 uint64_t
next()155 V3DDriver::next()
156 {
157 auto ret = last_dump_ts;
158 last_dump_ts = 0;
159 return ret;
160 }
161
162 uint32_t
gpu_clock_id() const163 V3DDriver::gpu_clock_id() const
164 {
165 return perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME;
166 }
167
168 uint64_t
gpu_timestamp() const169 V3DDriver::gpu_timestamp() const
170 {
171 return perfetto::base::GetBootTimeNs().count();
172 }
173
174 bool
cpu_gpu_timestamp(uint64_t &,uint64_t &) const175 V3DDriver::cpu_gpu_timestamp(uint64_t &, uint64_t &) const
176 {
177 /* Not supported */
178 return false;
179 }
180
181 } // namespace pps
182