1 /*
2 * Copyright © 2019-2021 Collabora, Ltd.
3 * Author: Antonio Caggiano <antonio.caggiano@collabora.com>
4 * Author: Rohan Garg <rohan.garg@collabora.com>
5 * Author: Robert Beckett <bob.beckett@collabora.com>
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
24 {
PanfrostDriver()25 PanfrostDriver::PanfrostDriver()
26 {
27 }
28
~PanfrostDriver()29 PanfrostDriver::~PanfrostDriver()
30 {
31 }
32
get_min_sampling_period_ns()33 uint64_t PanfrostDriver::get_min_sampling_period_ns()
34 {
35 return 1000000;
36 }
37
find_id_within_group(uint32_t counter_id,const struct panfrost_perf_config * cfg)38 uint32_t find_id_within_group(uint32_t counter_id, const struct panfrost_perf_config *cfg)
39 {
40 for (uint32_t cat_id = 0; cat_id < cfg->n_categories; ++cat_id) {
41 const struct panfrost_perf_category *cat = &cfg->categories[cat_id];
42 if (counter_id < cat->n_counters) {
43 break;
44 }
45 counter_id -= cat->n_counters;
46 }
47
48 return counter_id;
49 }
50
51 std::pair<std::vector<CounterGroup>, std::vector<Counter>>
create_available_counters(const PanfrostPerf & perf)52 PanfrostDriver::create_available_counters(const PanfrostPerf &perf)
53 {
54 std::pair<std::vector<CounterGroup>, std::vector<Counter>> ret;
55 auto &[groups, counters] = ret;
56
57 size_t cid = 0;
58
59 for (uint32_t gid = 0; gid < perf.perf->cfg->n_categories; ++gid) {
60 const auto &category = perf.perf->cfg->categories[gid];
61 CounterGroup group = {};
62 group.id = gid;
63 group.name = category.name;
64
65 for (; cid < category.n_counters; ++cid) {
66 Counter counter = {};
67 counter.id = cid;
68 counter.group = gid;
69
70 uint32_t id_within_group = find_id_within_group(cid, perf.perf->cfg);
71 counter.name = category.counters[id_within_group].name;
72
73 counter.set_getter([](const Counter &c, const Driver &d) {
74 auto &pan_driver = PanfrostDriver::into(d);
75 struct panfrost_perf *perf = pan_driver.perf->perf;
76 uint32_t id_within_group = find_id_within_group(c.id, perf->cfg);
77 const auto counter = &perf->cfg->categories[c.group].counters[id_within_group];
78 return int64_t(panfrost_perf_counter_read(counter, perf));
79 });
80
81 group.counters.push_back(cid);
82
83 counters.emplace_back(counter);
84 }
85
86 groups.push_back(group);
87 }
88
89 return ret;
90 }
91
init_perfcnt()92 bool PanfrostDriver::init_perfcnt()
93 {
94 if (!dev) {
95 dev = std::make_unique<PanfrostDevice>(drm_device.fd);
96 }
97 if (!perf) {
98 perf = std::make_unique<PanfrostPerf>(*dev);
99 }
100 if (groups.empty() && counters.empty()) {
101 std::tie(groups, counters) = create_available_counters(*perf);
102 }
103 return true;
104 }
105
enable_counter(const uint32_t counter_id)106 void PanfrostDriver::enable_counter(const uint32_t counter_id)
107 {
108 enabled_counters.push_back(counters[counter_id]);
109 }
110
enable_all_counters()111 void PanfrostDriver::enable_all_counters()
112 {
113 enabled_counters.resize(counters.size());
114 for (size_t i = 0; i < counters.size(); ++i) {
115 enabled_counters[i] = counters[i];
116 }
117 }
118
enable_perfcnt(const uint64_t)119 void PanfrostDriver::enable_perfcnt(const uint64_t /* sampling_period_ns */)
120 {
121 auto res = perf->enable();
122 if (!check(res, "Failed to enable performance counters")) {
123 if (res == -ENOSYS) {
124 PERFETTO_FATAL("Please enable unstable ioctls with: modprobe panfrost unstable_ioctls=1");
125 }
126 PERFETTO_FATAL("Please verify graphics card");
127 }
128 }
129
dump_perfcnt()130 bool PanfrostDriver::dump_perfcnt()
131 {
132 last_dump_ts = perfetto::base::GetBootTimeNs().count();
133
134 // Dump performance counters to buffer
135 if (!check(perf->dump(), "Failed to dump performance counters")) {
136 PERFETTO_ELOG("Skipping sample");
137 return false;
138 }
139
140 return true;
141 }
142
next()143 uint64_t PanfrostDriver::next()
144 {
145 auto ret = last_dump_ts;
146 last_dump_ts = 0;
147 return ret;
148 }
149
disable_perfcnt()150 void PanfrostDriver::disable_perfcnt()
151 {
152 perf->disable();
153 perf.reset();
154 dev.reset();
155 groups.clear();
156 counters.clear();
157 enabled_counters.clear();
158 }
159
160 } // namespace pps
161