• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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