1 /*
2 * Copyright © 2019-2021 Collabora, Ltd.
3 * Author: Antonio Caggiano <[email protected]>
4 * Author: Rohan Garg <[email protected]>
5 * Author: Robert Beckett <[email protected]>
6 *
7 * SPDX-License-Identifier: MIT
8 */
9
10 #include "pan_pps_driver.h"
11
12 #include <cstring>
13 #include <perfetto.h>
14 #include <xf86drm.h>
15
16 #include <drm-uapi/panfrost_drm.h>
17 #include <perf/pan_perf.h>
18 #include <util/macros.h>
19
20 #include <pps/pps.h>
21 #include <pps/pps_algorithm.h>
22
23 namespace pps {
PanfrostDriver()24 PanfrostDriver::PanfrostDriver()
25 {
26 }
27
~PanfrostDriver()28 PanfrostDriver::~PanfrostDriver()
29 {
30 }
31
32 uint64_t
get_min_sampling_period_ns()33 PanfrostDriver::get_min_sampling_period_ns()
34 {
35 return 1000000;
36 }
37
38 uint32_t
find_id_within_group(uint32_t counter_id,const struct panfrost_perf_config * cfg)39 find_id_within_group(uint32_t counter_id,
40 const struct panfrost_perf_config *cfg)
41 {
42 for (uint32_t cat_id = 0; cat_id < cfg->n_categories; ++cat_id) {
43 const struct panfrost_perf_category *cat = &cfg->categories[cat_id];
44 if (counter_id < cat->n_counters) {
45 break;
46 }
47 counter_id -= cat->n_counters;
48 }
49
50 return counter_id;
51 }
52
53 std::pair<std::vector<CounterGroup>, std::vector<Counter>>
create_available_counters(const PanfrostPerf & perf)54 PanfrostDriver::create_available_counters(const PanfrostPerf &perf)
55 {
56 std::pair<std::vector<CounterGroup>, std::vector<Counter>> ret;
57 auto &[groups, counters] = ret;
58
59 size_t cid = 0;
60
61 for (uint32_t gid = 0; gid < perf.perf->cfg->n_categories; ++gid) {
62 const auto &category = perf.perf->cfg->categories[gid];
63 CounterGroup group = {};
64 group.id = gid;
65 group.name = category.name;
66
67 for (; cid < category.n_counters; ++cid) {
68 Counter counter = {};
69 counter.id = cid;
70 counter.group = gid;
71
72 uint32_t id_within_group = find_id_within_group(cid, perf.perf->cfg);
73 counter.name = category.counters[id_within_group].name;
74
75 counter.set_getter([](const Counter &c, const Driver &d) {
76 auto &pan_driver = PanfrostDriver::into(d);
77 struct panfrost_perf *perf = pan_driver.perf->perf;
78 uint32_t id_within_group = find_id_within_group(c.id, perf->cfg);
79 const auto counter =
80 &perf->cfg->categories[c.group].counters[id_within_group];
81 return int64_t(panfrost_perf_counter_read(counter, perf));
82 });
83
84 group.counters.push_back(cid);
85
86 counters.emplace_back(counter);
87 }
88
89 groups.push_back(group);
90 }
91
92 return ret;
93 }
94
95 bool
init_perfcnt()96 PanfrostDriver::init_perfcnt()
97 {
98 if (!dev) {
99 dev = std::make_unique<PanfrostDevice>(drm_device.fd);
100 }
101 if (!perf) {
102 perf = std::make_unique<PanfrostPerf>(*dev);
103 }
104 if (groups.empty() && counters.empty()) {
105 std::tie(groups, counters) = create_available_counters(*perf);
106 }
107 return true;
108 }
109
110 void
enable_counter(const uint32_t counter_id)111 PanfrostDriver::enable_counter(const uint32_t counter_id)
112 {
113 enabled_counters.push_back(counters[counter_id]);
114 }
115
116 void
enable_all_counters()117 PanfrostDriver::enable_all_counters()
118 {
119 enabled_counters.resize(counters.size());
120 for (size_t i = 0; i < counters.size(); ++i) {
121 enabled_counters[i] = counters[i];
122 }
123 }
124
125 void
enable_perfcnt(const uint64_t)126 PanfrostDriver::enable_perfcnt(const uint64_t /* sampling_period_ns */)
127 {
128 auto res = perf->enable();
129 if (!check(res, "Failed to enable performance counters")) {
130 if (res == -ENOSYS) {
131 PERFETTO_FATAL(
132 "Please enable unstable ioctls with: modprobe panfrost unstable_ioctls=1");
133 }
134 PERFETTO_FATAL("Please verify graphics card");
135 }
136 }
137
138 bool
dump_perfcnt()139 PanfrostDriver::dump_perfcnt()
140 {
141 last_dump_ts = perfetto::base::GetBootTimeNs().count();
142
143 // Dump performance counters to buffer
144 if (!check(perf->dump(), "Failed to dump performance counters")) {
145 PERFETTO_ELOG("Skipping sample");
146 return false;
147 }
148
149 return true;
150 }
151
152 uint64_t
next()153 PanfrostDriver::next()
154 {
155 auto ret = last_dump_ts;
156 last_dump_ts = 0;
157 return ret;
158 }
159
160 void
disable_perfcnt()161 PanfrostDriver::disable_perfcnt()
162 {
163 perf->disable();
164 perf.reset();
165 dev.reset();
166 groups.clear();
167 counters.clear();
168 enabled_counters.clear();
169 }
170
171 uint32_t
gpu_clock_id() const172 PanfrostDriver::gpu_clock_id() const
173 {
174 return perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME;
175 }
176
177 uint64_t
gpu_timestamp() const178 PanfrostDriver::gpu_timestamp() const
179 {
180 return perfetto::base::GetBootTimeNs().count();
181 }
182
183 bool
cpu_gpu_timestamp(uint64_t &,uint64_t &) const184 PanfrostDriver::cpu_gpu_timestamp(uint64_t &, uint64_t &) const
185 {
186 /* Not supported */
187 return false;
188 }
189
190 } // namespace pps
191