blob: f36d1801a30f8ce372cf05f21209fb0ef821c69b [file] [log] [blame]
Moritz Pflanzer45634b42017-08-30 12:48:18 +01001/*
2 * Copyright (c) 2017 ARM Limited.
3 *
4 * SPDX-License-Identifier: MIT
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24#include "MaliCounter.h"
25
Anthony Barbier144d2ff2017-09-29 10:46:08 +010026#include "arm_compute/core/Error.h"
27
Moritz Pflanzer45634b42017-08-30 12:48:18 +010028namespace arm_compute
29{
30namespace test
31{
32namespace framework
33{
34namespace
35{
36struct MaliHWInfo
37{
38 unsigned mp_count;
39 unsigned gpu_id;
40 unsigned r_value;
41 unsigned p_value;
42 unsigned core_mask;
43};
44
45MaliHWInfo get_mali_hw_info(const char *path)
46{
47 int fd = open(path, O_RDWR); // NOLINT
48
49 if(fd < 0)
50 {
Anthony Barbier144d2ff2017-09-29 10:46:08 +010051 ARM_COMPUTE_ERROR("Failed to get HW info.");
Moritz Pflanzer45634b42017-08-30 12:48:18 +010052 }
53
54 {
55 mali_userspace::uku_version_check_args version_check_args; // NOLINT
56 version_check_args.header.id = mali_userspace::UKP_FUNC_ID_CHECK_VERSION; // NOLINT
57 version_check_args.major = 10;
58 version_check_args.minor = 2;
59
60 if(mali_userspace::mali_ioctl(fd, version_check_args) != 0)
61 {
Anthony Barbier144d2ff2017-09-29 10:46:08 +010062 ARM_COMPUTE_ERROR("Failed to check version.");
Moritz Pflanzer45634b42017-08-30 12:48:18 +010063 close(fd);
64 }
65 }
66
67 {
68 mali_userspace::kbase_uk_hwcnt_reader_set_flags flags; // NOLINT
69 memset(&flags, 0, sizeof(flags));
70 flags.header.id = mali_userspace::KBASE_FUNC_SET_FLAGS; // NOLINT
71 flags.create_flags = mali_userspace::BASE_CONTEXT_CREATE_KERNEL_FLAGS;
72
73 if(mali_userspace::mali_ioctl(fd, flags) != 0)
74 {
Anthony Barbier144d2ff2017-09-29 10:46:08 +010075 ARM_COMPUTE_ERROR("Failed settings flags ioctl.");
Moritz Pflanzer45634b42017-08-30 12:48:18 +010076 close(fd);
77 }
78 }
79
80 {
81 mali_userspace::kbase_uk_gpuprops props; // NOLINT
82 props.header.id = mali_userspace::KBASE_FUNC_GPU_PROPS_REG_DUMP; // NOLINT
83
84 if(mali_ioctl(fd, props) != 0)
85 {
Anthony Barbier144d2ff2017-09-29 10:46:08 +010086 ARM_COMPUTE_ERROR("Failed settings flags ioctl.");
Moritz Pflanzer45634b42017-08-30 12:48:18 +010087 close(fd);
88 }
89
90 MaliHWInfo hw_info; // NOLINT
91 memset(&hw_info, 0, sizeof(hw_info));
92 hw_info.gpu_id = props.props.core_props.product_id;
93 hw_info.r_value = props.props.core_props.major_revision;
94 hw_info.p_value = props.props.core_props.minor_revision;
95
96 for(unsigned int i = 0; i < props.props.coherency_info.num_core_groups; ++i)
97 {
98 hw_info.core_mask |= props.props.coherency_info.group[i].core_mask;
99 }
100
101 hw_info.mp_count = __builtin_popcountll(hw_info.core_mask);
102
103 close(fd);
104
105 return hw_info;
106 }
107}
108} // namespace
109
110MaliCounter::MaliCounter()
111{
112 _counters =
113 {
Anthony Barbierab14c152017-11-09 10:29:59 +0000114 { "GPU_ACTIVE", Measurement(0, "cycles") },
Moritz Pflanzer45634b42017-08-30 12:48:18 +0100115 };
116
117 _core_counters =
118 {
119 { "ARITH_WORDS", { "Arithmetic pipe", std::map<int, uint64_t>(), "instructions" } },
120 { "LS_ISSUE", { "LS pipe", std::map<int, uint64_t>(), "instructions" } },
121 { "TEX_ISSUE", { "Texture pipe", std::map<int, uint64_t>(), "instructions" } },
122 { "COMPUTE_ACTIVE", { "Compute core", std::map<int, uint64_t>(), "cycles" } },
123 { "FRAG_ACTIVE", { "Fragment core", std::map<int, uint64_t>(), "cycles" } },
124 };
125
126 init();
127}
128
129MaliCounter::~MaliCounter()
130{
131 term();
132}
133
134void MaliCounter::init()
135{
136 term();
137
138 MaliHWInfo hw_info = get_mali_hw_info(_device);
139
140 _num_cores = hw_info.mp_count;
141
142 _fd = open(_device, O_RDWR | O_CLOEXEC | O_NONBLOCK); // NOLINT
143
144 if(_fd < 0)
145 {
Anthony Barbier144d2ff2017-09-29 10:46:08 +0100146 ARM_COMPUTE_ERROR("Failed to open /dev/mali0.");
Moritz Pflanzer45634b42017-08-30 12:48:18 +0100147 }
148
149 {
150 mali_userspace::kbase_uk_hwcnt_reader_version_check_args check; // NOLINT
151 memset(&check, 0, sizeof(check));
152
153 if(mali_userspace::mali_ioctl(_fd, check) != 0)
154 {
Anthony Barbier144d2ff2017-09-29 10:46:08 +0100155 ARM_COMPUTE_ERROR("Failed to get ABI version.");
Moritz Pflanzer45634b42017-08-30 12:48:18 +0100156 }
157 else if(check.major < 10)
158 {
Anthony Barbier144d2ff2017-09-29 10:46:08 +0100159 ARM_COMPUTE_ERROR("Unsupported ABI version 10.");
Moritz Pflanzer45634b42017-08-30 12:48:18 +0100160 }
161 }
162
163 {
164 mali_userspace::kbase_uk_hwcnt_reader_set_flags flags; // NOLINT
165 memset(&flags, 0, sizeof(flags));
166 flags.header.id = mali_userspace::KBASE_FUNC_SET_FLAGS; // NOLINT
167 flags.create_flags = mali_userspace::BASE_CONTEXT_CREATE_KERNEL_FLAGS;
168
169 if(mali_userspace::mali_ioctl(_fd, flags) != 0)
170 {
Anthony Barbier144d2ff2017-09-29 10:46:08 +0100171 ARM_COMPUTE_ERROR("Failed settings flags ioctl.");
Moritz Pflanzer45634b42017-08-30 12:48:18 +0100172 }
173 }
174
175 {
176 mali_userspace::kbase_uk_hwcnt_reader_setup setup; // NOLINT
177 memset(&setup, 0, sizeof(setup));
178 setup.header.id = mali_userspace::KBASE_FUNC_HWCNT_READER_SETUP; // NOLINT
179 setup.buffer_count = _buffer_count;
180 setup.jm_bm = -1;
181 setup.shader_bm = -1;
182 setup.tiler_bm = -1;
183 setup.mmu_l2_bm = -1;
184 setup.fd = -1;
185
186 if(mali_userspace::mali_ioctl(_fd, setup) != 0)
187 {
Anthony Barbier144d2ff2017-09-29 10:46:08 +0100188 ARM_COMPUTE_ERROR("Failed setting hwcnt reader ioctl.");
Moritz Pflanzer45634b42017-08-30 12:48:18 +0100189 }
190
191 _hwc_fd = setup.fd;
192 }
193
194 {
195 uint32_t api_version = ~mali_userspace::HWCNT_READER_API;
196
197 if(ioctl(_hwc_fd, mali_userspace::KBASE_HWCNT_READER_GET_API_VERSION, &api_version) != 0) // NOLINT
198 {
Anthony Barbier144d2ff2017-09-29 10:46:08 +0100199 ARM_COMPUTE_ERROR("Could not determine hwcnt reader API.");
Moritz Pflanzer45634b42017-08-30 12:48:18 +0100200 }
201 else if(api_version != mali_userspace::HWCNT_READER_API)
202 {
Anthony Barbier144d2ff2017-09-29 10:46:08 +0100203 ARM_COMPUTE_ERROR("Invalid API version.");
Moritz Pflanzer45634b42017-08-30 12:48:18 +0100204 }
205 }
206
Moritz Pflanzer29088d52017-09-21 15:06:59 +0100207 if(ioctl(_hwc_fd, static_cast<int>(mali_userspace::KBASE_HWCNT_READER_GET_BUFFER_SIZE), &_buffer_size) != 0) // NOLINT
Moritz Pflanzer45634b42017-08-30 12:48:18 +0100208 {
Anthony Barbier144d2ff2017-09-29 10:46:08 +0100209 ARM_COMPUTE_ERROR("Failed to get buffer size.");
Moritz Pflanzer45634b42017-08-30 12:48:18 +0100210 }
211
Moritz Pflanzer29088d52017-09-21 15:06:59 +0100212 if(ioctl(_hwc_fd, static_cast<int>(mali_userspace::KBASE_HWCNT_READER_GET_HWVER), &_hw_ver) != 0) // NOLINT
Moritz Pflanzer45634b42017-08-30 12:48:18 +0100213 {
Anthony Barbier144d2ff2017-09-29 10:46:08 +0100214 ARM_COMPUTE_ERROR("Could not determine HW version.");
Moritz Pflanzer45634b42017-08-30 12:48:18 +0100215 }
216
217 if(_hw_ver < 5)
218 {
Anthony Barbier144d2ff2017-09-29 10:46:08 +0100219 ARM_COMPUTE_ERROR("Unsupported HW version.");
Moritz Pflanzer45634b42017-08-30 12:48:18 +0100220 }
221
222 _sample_data = static_cast<uint8_t *>(mmap(nullptr, _buffer_count * _buffer_size, PROT_READ, MAP_PRIVATE, _hwc_fd, 0));
223
224 if(_sample_data == MAP_FAILED) // NOLINT
225 {
Anthony Barbier144d2ff2017-09-29 10:46:08 +0100226 ARM_COMPUTE_ERROR("Failed to map sample data.");
Moritz Pflanzer45634b42017-08-30 12:48:18 +0100227 }
228
229 auto product = std::find_if(std::begin(mali_userspace::products), std::end(mali_userspace::products), [&](const mali_userspace::CounterMapping & cm)
230 {
231 return (cm.product_mask & hw_info.gpu_id) == cm.product_id;
232 });
233
234 if(product != std::end(mali_userspace::products))
235 {
236 _names_lut = product->names_lut;
237 }
238 else
239 {
Anthony Barbier144d2ff2017-09-29 10:46:08 +0100240 ARM_COMPUTE_ERROR("Could not identify GPU.");
Moritz Pflanzer45634b42017-08-30 12:48:18 +0100241 }
242
243 _raw_counter_buffer.resize(_buffer_size / sizeof(uint32_t));
244
245 // Build core remap table.
246 _core_index_remap.clear();
247 _core_index_remap.reserve(hw_info.mp_count);
248
249 unsigned int mask = hw_info.core_mask;
250
251 while(mask != 0)
252 {
253 unsigned int bit = __builtin_ctz(mask);
254 _core_index_remap.push_back(bit);
255 mask &= ~(1u << bit);
256 }
257}
258
259void MaliCounter::term()
260{
261 if(_sample_data != nullptr)
262 {
263 munmap(_sample_data, _buffer_count * _buffer_size);
264 _sample_data = nullptr;
265 }
266
267 if(_hwc_fd >= 0)
268 {
269 close(_hwc_fd);
270 _hwc_fd = -1;
271 }
272
273 if(_fd >= 0)
274 {
275 close(_fd);
276 _fd = -1;
277 }
278}
279
280void MaliCounter::sample_counters()
281{
282 if(ioctl(_hwc_fd, mali_userspace::KBASE_HWCNT_READER_DUMP, 0) != 0)
283 {
Anthony Barbier144d2ff2017-09-29 10:46:08 +0100284 ARM_COMPUTE_ERROR("Could not sample hardware counters.");
Moritz Pflanzer45634b42017-08-30 12:48:18 +0100285 }
286}
287
288void MaliCounter::wait_next_event()
289{
290 pollfd poll_fd; // NOLINT
291 poll_fd.fd = _hwc_fd;
292 poll_fd.events = POLLIN;
293
294 const int count = poll(&poll_fd, 1, -1);
295
296 if(count < 0)
297 {
Anthony Barbier144d2ff2017-09-29 10:46:08 +0100298 ARM_COMPUTE_ERROR("poll() failed.");
Moritz Pflanzer45634b42017-08-30 12:48:18 +0100299 }
300
301 if((poll_fd.revents & POLLIN) != 0)
302 {
303 mali_userspace::kbase_hwcnt_reader_metadata meta; // NOLINT
304
Moritz Pflanzer29088d52017-09-21 15:06:59 +0100305 if(ioctl(_hwc_fd, static_cast<int>(mali_userspace::KBASE_HWCNT_READER_GET_BUFFER), &meta) != 0) // NOLINT
Moritz Pflanzer45634b42017-08-30 12:48:18 +0100306 {
Anthony Barbier144d2ff2017-09-29 10:46:08 +0100307 ARM_COMPUTE_ERROR("Failed READER_GET_BUFFER.");
Moritz Pflanzer45634b42017-08-30 12:48:18 +0100308 }
309
310 memcpy(_raw_counter_buffer.data(), _sample_data + _buffer_size * meta.buffer_idx, _buffer_size);
311 _timestamp = meta.timestamp;
312
313 if(ioctl(_hwc_fd, mali_userspace::KBASE_HWCNT_READER_PUT_BUFFER, &meta) != 0) // NOLINT
314 {
Anthony Barbier144d2ff2017-09-29 10:46:08 +0100315 ARM_COMPUTE_ERROR("Failed READER_PUT_BUFFER.");
Moritz Pflanzer45634b42017-08-30 12:48:18 +0100316 }
317 }
318 else if((poll_fd.revents & POLLHUP) != 0)
319 {
Anthony Barbier144d2ff2017-09-29 10:46:08 +0100320 ARM_COMPUTE_ERROR("HWC hung up.");
Moritz Pflanzer45634b42017-08-30 12:48:18 +0100321 }
322}
323
324const uint32_t *MaliCounter::get_counters() const
325{
326 return _raw_counter_buffer.data();
327}
328
329const uint32_t *MaliCounter::get_counters(mali_userspace::MaliCounterBlockName block, int core) const
330{
331 switch(block)
332 {
333 case mali_userspace::MALI_NAME_BLOCK_JM:
334 return _raw_counter_buffer.data() + mali_userspace::MALI_NAME_BLOCK_SIZE * 0;
335 case mali_userspace::MALI_NAME_BLOCK_MMU:
336 return _raw_counter_buffer.data() + mali_userspace::MALI_NAME_BLOCK_SIZE * 2;
337 case mali_userspace::MALI_NAME_BLOCK_TILER:
338 return _raw_counter_buffer.data() + mali_userspace::MALI_NAME_BLOCK_SIZE * 1;
339 default:
340 if(core < 0)
341 {
Anthony Barbier144d2ff2017-09-29 10:46:08 +0100342 ARM_COMPUTE_ERROR("Invalid core number.");
Moritz Pflanzer45634b42017-08-30 12:48:18 +0100343 }
344
345 return _raw_counter_buffer.data() + mali_userspace::MALI_NAME_BLOCK_SIZE * (3 + _core_index_remap[core]);
346 }
347}
348
349int MaliCounter::find_counter_index_by_name(mali_userspace::MaliCounterBlockName block, const char *name)
350{
351 const char *const *names = &_names_lut[mali_userspace::MALI_NAME_BLOCK_SIZE * block];
352
353 for(int i = 0; i < mali_userspace::MALI_NAME_BLOCK_SIZE; ++i)
354 {
355 if(strstr(names[i], name) != nullptr)
356 {
357 return i;
358 }
359 }
360
361 return -1;
362}
363
364void MaliCounter::start()
365{
366 sample_counters();
367 wait_next_event();
368 _start_time = _timestamp;
369}
370
371void MaliCounter::stop()
372{
373 sample_counters();
374 wait_next_event();
375
Anthony Barbierab14c152017-11-09 10:29:59 +0000376 const uint32_t *counter = get_counters(mali_userspace::MALI_NAME_BLOCK_JM);
377 _counters.at("GPU_ACTIVE") = Measurement(counter[find_counter_index_by_name(mali_userspace::MALI_NAME_BLOCK_JM, "GPU_ACTIVE")], _counters.at("GPU_ACTIVE").unit());
Moritz Pflanzer45634b42017-08-30 12:48:18 +0100378
379 const int arith_index = find_counter_index_by_name(mali_userspace::MALI_NAME_BLOCK_SHADER, "ARITH_WORDS");
380 const int ls_index = find_counter_index_by_name(mali_userspace::MALI_NAME_BLOCK_SHADER, "LS_ISSUE");
381 const int tex_index = find_counter_index_by_name(mali_userspace::MALI_NAME_BLOCK_SHADER, "TEX_ISSUE");
382 const int compute_index = find_counter_index_by_name(mali_userspace::MALI_NAME_BLOCK_SHADER, "COMPUTE_ACTIVE");
383 const int frag_index = find_counter_index_by_name(mali_userspace::MALI_NAME_BLOCK_SHADER, "FRAG_ACTIVE");
384
385 // Shader core counters can be averaged if desired, but here we don't.
386 for(int core = 0; core < _num_cores; ++core)
387 {
Anthony Barbierab14c152017-11-09 10:29:59 +0000388 const uint32_t *sc_counter = get_counters(mali_userspace::MALI_NAME_BLOCK_SHADER, core);
Moritz Pflanzer45634b42017-08-30 12:48:18 +0100389
390 _core_counters.at("ARITH_WORDS").values[core] = sc_counter[arith_index];
391 _core_counters.at("LS_ISSUE").values[core] = sc_counter[ls_index];
392 _core_counters.at("TEX_ISSUE").values[core] = sc_counter[tex_index];
393 _core_counters.at("COMPUTE_ACTIVE").values[core] = sc_counter[compute_index];
394 _core_counters.at("FRAG_ACTIVE").values[core] = sc_counter[frag_index];
395 }
396
397 _stop_time = _timestamp;
398}
399
400std::string MaliCounter::id() const
401{
402 return "Mali Counter";
403}
404
405Instrument::MeasurementsMap MaliCounter::measurements() const
406{
407 MeasurementsMap measurements
408 {
Anthony Barbierab14c152017-11-09 10:29:59 +0000409 { "Timespan", Measurement(_stop_time - _start_time, "ns") },
Moritz Pflanzer45634b42017-08-30 12:48:18 +0100410 { "GPU active", _counters.at("GPU_ACTIVE") },
411 };
412
413 for(const auto &counter : _core_counters)
414 {
415 for(const auto &core : counter.second.values)
416 {
Anthony Barbierab14c152017-11-09 10:29:59 +0000417 measurements.emplace(counter.second.name + " #" + support::cpp11::to_string(core.first), Measurement(core.second, counter.second.unit));
Moritz Pflanzer45634b42017-08-30 12:48:18 +0100418 }
419 }
420
421 return measurements;
422}
423} // namespace framework
424} // namespace test
425} // namespace arm_compute