Compute Library
 21.02
MaliCounter.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017-2019 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 
26 #include "arm_compute/core/Error.h"
27 
28 namespace arm_compute
29 {
30 namespace test
31 {
32 namespace framework
33 {
34 namespace
35 {
36 struct MaliHWInfo
37 {
38  unsigned mp_count;
39  unsigned gpu_id;
40  unsigned r_value;
41  unsigned p_value;
42  unsigned core_mask;
43 };
44 
45 MaliHWInfo get_mali_hw_info(const char *path)
46 {
47  int fd = open(path, O_RDWR); // NOLINT
48 
49  if(fd < 0)
50  {
51  ARM_COMPUTE_ERROR("Failed to get HW info.");
52  }
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  {
62  ARM_COMPUTE_ERROR("Failed to check version.");
63  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  {
75  ARM_COMPUTE_ERROR("Failed settings flags ioctl.");
76  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  {
86  ARM_COMPUTE_ERROR("Failed settings flags ioctl.");
87  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 
111 {
112  _counters =
113  {
114  { "GPU_ACTIVE", Measurement(0, "cycles") },
115  };
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  switch(scale_factor)
127  {
128  case ScaleFactor::NONE:
129  _scale_factor = 1;
130  _unit = "";
131  break;
133  _scale_factor = 1000;
134  _unit = "K ";
135  break;
137  _scale_factor = 1000000;
138  _unit = "M ";
139  break;
140  default:
141  ARM_COMPUTE_ERROR("Invalid scale");
142  }
143 
144  init();
145 }
146 
148 {
149  term();
150 }
151 
152 void MaliCounter::init()
153 {
154  term();
155 
156  MaliHWInfo hw_info = get_mali_hw_info(_device);
157 
158  _num_cores = hw_info.mp_count;
159 
160  _fd = open(_device, O_RDWR | O_CLOEXEC | O_NONBLOCK); // NOLINT
161 
162  if(_fd < 0)
163  {
164  ARM_COMPUTE_ERROR("Failed to open /dev/mali0.");
165  }
166 
167  {
168  mali_userspace::kbase_uk_hwcnt_reader_version_check_args check; // NOLINT
169  memset(&check, 0, sizeof(check));
170 
171  if(mali_userspace::mali_ioctl(_fd, check) != 0)
172  {
173  ARM_COMPUTE_ERROR("Failed to get ABI version.");
174  }
175  else if(check.major < 10)
176  {
177  ARM_COMPUTE_ERROR("Unsupported ABI version 10.");
178  }
179  }
180 
181  {
182  mali_userspace::kbase_uk_hwcnt_reader_set_flags flags; // NOLINT
183  memset(&flags, 0, sizeof(flags));
184  flags.header.id = mali_userspace::KBASE_FUNC_SET_FLAGS; // NOLINT
185  flags.create_flags = mali_userspace::BASE_CONTEXT_CREATE_KERNEL_FLAGS;
186 
187  if(mali_userspace::mali_ioctl(_fd, flags) != 0)
188  {
189  ARM_COMPUTE_ERROR("Failed settings flags ioctl.");
190  }
191  }
192 
193  {
194  mali_userspace::kbase_uk_hwcnt_reader_setup setup; // NOLINT
195  memset(&setup, 0, sizeof(setup));
196  setup.header.id = mali_userspace::KBASE_FUNC_HWCNT_READER_SETUP; // NOLINT
197  setup.buffer_count = _buffer_count;
198  setup.jm_bm = -1;
199  setup.shader_bm = -1;
200  setup.tiler_bm = -1;
201  setup.mmu_l2_bm = -1;
202  setup.fd = -1;
203 
204  if(mali_userspace::mali_ioctl(_fd, setup) != 0)
205  {
206  ARM_COMPUTE_ERROR("Failed setting hwcnt reader ioctl.");
207  }
208 
209  _hwc_fd = setup.fd;
210  }
211 
212  {
213  uint32_t api_version = ~mali_userspace::HWCNT_READER_API;
214 
215  if(ioctl(_hwc_fd, mali_userspace::KBASE_HWCNT_READER_GET_API_VERSION, &api_version) != 0) // NOLINT
216  {
217  ARM_COMPUTE_ERROR("Could not determine hwcnt reader API.");
218  }
219  else if(api_version != mali_userspace::HWCNT_READER_API)
220  {
221  ARM_COMPUTE_ERROR("Invalid API version.");
222  }
223  }
224 
225  if(ioctl(_hwc_fd, static_cast<int>(mali_userspace::KBASE_HWCNT_READER_GET_BUFFER_SIZE), &_buffer_size) != 0) // NOLINT
226  {
227  ARM_COMPUTE_ERROR("Failed to get buffer size.");
228  }
229 
230  if(ioctl(_hwc_fd, static_cast<int>(mali_userspace::KBASE_HWCNT_READER_GET_HWVER), &_hw_ver) != 0) // NOLINT
231  {
232  ARM_COMPUTE_ERROR("Could not determine HW version.");
233  }
234 
235  if(_hw_ver < 5)
236  {
237  ARM_COMPUTE_ERROR("Unsupported HW version.");
238  }
239 
240  _sample_data = static_cast<uint8_t *>(mmap(nullptr, _buffer_count * _buffer_size, PROT_READ, MAP_PRIVATE, _hwc_fd, 0));
241 
242  if(_sample_data == MAP_FAILED) // NOLINT
243  {
244  ARM_COMPUTE_ERROR("Failed to map sample data.");
245  }
246 
247  auto product = std::find_if(std::begin(mali_userspace::products), std::end(mali_userspace::products), [&](const mali_userspace::CounterMapping & cm)
248  {
249  return (cm.product_mask & hw_info.gpu_id) == cm.product_id;
250  });
251 
252  if(product != std::end(mali_userspace::products))
253  {
254  _names_lut = product->names_lut;
255  }
256  else
257  {
258  ARM_COMPUTE_ERROR("Could not identify GPU.");
259  }
260 
261  _raw_counter_buffer.resize(_buffer_size / sizeof(uint32_t));
262 
263  // Build core remap table.
264  _core_index_remap.clear();
265  _core_index_remap.reserve(hw_info.mp_count);
266 
267  unsigned int mask = hw_info.core_mask;
268 
269  while(mask != 0)
270  {
271  unsigned int bit = __builtin_ctz(mask);
272  _core_index_remap.push_back(bit);
273  mask &= ~(1u << bit);
274  }
275 }
276 
277 void MaliCounter::term()
278 {
279  if(_sample_data != nullptr)
280  {
281  munmap(_sample_data, _buffer_count * _buffer_size);
282  _sample_data = nullptr;
283  }
284 
285  if(_hwc_fd >= 0)
286  {
287  close(_hwc_fd);
288  _hwc_fd = -1;
289  }
290 
291  if(_fd >= 0)
292  {
293  close(_fd);
294  _fd = -1;
295  }
296 }
297 
298 void MaliCounter::sample_counters()
299 {
300  if(ioctl(_hwc_fd, mali_userspace::KBASE_HWCNT_READER_DUMP, 0) != 0)
301  {
302  ARM_COMPUTE_ERROR("Could not sample hardware counters.");
303  }
304 }
305 
306 void MaliCounter::wait_next_event()
307 {
308  pollfd poll_fd; // NOLINT
309  poll_fd.fd = _hwc_fd;
310  poll_fd.events = POLLIN;
311 
312  const int count = poll(&poll_fd, 1, -1);
313 
314  if(count < 0)
315  {
316  ARM_COMPUTE_ERROR("poll() failed.");
317  }
318 
319  if((poll_fd.revents & POLLIN) != 0)
320  {
321  mali_userspace::kbase_hwcnt_reader_metadata meta; // NOLINT
322 
323  if(ioctl(_hwc_fd, static_cast<int>(mali_userspace::KBASE_HWCNT_READER_GET_BUFFER), &meta) != 0) // NOLINT
324  {
325  ARM_COMPUTE_ERROR("Failed READER_GET_BUFFER.");
326  }
327 
328  memcpy(_raw_counter_buffer.data(), _sample_data + _buffer_size * meta.buffer_idx, _buffer_size);
329  _timestamp = meta.timestamp;
330 
331  if(ioctl(_hwc_fd, mali_userspace::KBASE_HWCNT_READER_PUT_BUFFER, &meta) != 0) // NOLINT
332  {
333  ARM_COMPUTE_ERROR("Failed READER_PUT_BUFFER.");
334  }
335  }
336  else if((poll_fd.revents & POLLHUP) != 0)
337  {
338  ARM_COMPUTE_ERROR("HWC hung up.");
339  }
340 }
341 
342 const uint32_t *MaliCounter::get_counters() const
343 {
344  return _raw_counter_buffer.data();
345 }
346 
347 const uint32_t *MaliCounter::get_counters(mali_userspace::MaliCounterBlockName block, int core) const
348 {
349  switch(block)
350  {
351  case mali_userspace::MALI_NAME_BLOCK_JM:
352  return _raw_counter_buffer.data() + mali_userspace::MALI_NAME_BLOCK_SIZE * 0;
353  case mali_userspace::MALI_NAME_BLOCK_MMU:
354  return _raw_counter_buffer.data() + mali_userspace::MALI_NAME_BLOCK_SIZE * 2;
355  case mali_userspace::MALI_NAME_BLOCK_TILER:
356  return _raw_counter_buffer.data() + mali_userspace::MALI_NAME_BLOCK_SIZE * 1;
357  default:
358  if(core < 0)
359  {
360  ARM_COMPUTE_ERROR("Invalid core number.");
361  }
362 
363  return _raw_counter_buffer.data() + mali_userspace::MALI_NAME_BLOCK_SIZE * (3 + _core_index_remap[core]);
364  }
365 }
366 
367 int MaliCounter::find_counter_index_by_name(mali_userspace::MaliCounterBlockName block, const char *name)
368 {
369  const char *const *names = &_names_lut[mali_userspace::MALI_NAME_BLOCK_SIZE * block];
370 
371  for(int i = 0; i < mali_userspace::MALI_NAME_BLOCK_SIZE; ++i)
372  {
373  if(strstr(names[i], name) != nullptr)
374  {
375  return i;
376  }
377  }
378 
379  return -1;
380 }
381 
383 {
384  sample_counters();
385  wait_next_event();
386  _start_time = _timestamp;
387 }
388 
390 {
391  sample_counters();
392  wait_next_event();
393 
394  const uint32_t *counter = get_counters(mali_userspace::MALI_NAME_BLOCK_JM);
395  _counters.at("GPU_ACTIVE") = Measurement(counter[find_counter_index_by_name(mali_userspace::MALI_NAME_BLOCK_JM, "GPU_ACTIVE")], _counters.at("GPU_ACTIVE").unit());
396 
397  const int arith_index = find_counter_index_by_name(mali_userspace::MALI_NAME_BLOCK_SHADER, "ARITH_WORDS");
398  const int ls_index = find_counter_index_by_name(mali_userspace::MALI_NAME_BLOCK_SHADER, "LS_ISSUE");
399  const int tex_index = find_counter_index_by_name(mali_userspace::MALI_NAME_BLOCK_SHADER, "TEX_ISSUE");
400  const int compute_index = find_counter_index_by_name(mali_userspace::MALI_NAME_BLOCK_SHADER, "COMPUTE_ACTIVE");
401  const int frag_index = find_counter_index_by_name(mali_userspace::MALI_NAME_BLOCK_SHADER, "FRAG_ACTIVE");
402 
403  // Shader core counters can be averaged if desired, but here we don't.
404  for(uint32_t core = 0; core < _num_cores; ++core)
405  {
406  const uint32_t *sc_counter = get_counters(mali_userspace::MALI_NAME_BLOCK_SHADER, core);
407 
408  _core_counters.at("ARITH_WORDS").values[core] = sc_counter[arith_index];
409  _core_counters.at("LS_ISSUE").values[core] = sc_counter[ls_index];
410  _core_counters.at("TEX_ISSUE").values[core] = sc_counter[tex_index];
411  _core_counters.at("COMPUTE_ACTIVE").values[core] = sc_counter[compute_index];
412  _core_counters.at("FRAG_ACTIVE").values[core] = sc_counter[frag_index];
413  }
414 
415  _stop_time = _timestamp;
416 }
417 
418 std::string MaliCounter::id() const
419 {
420  return "Mali Counter";
421 }
422 
424 {
425  Measurement counters((_counters.at("GPU_ACTIVE").value() / _scale_factor).v.floating_point, _unit + _counters.at("GPU_ACTIVE").unit()); //NOLINT
426 
427  MeasurementsMap measurements
428  {
429  { "Timespan", Measurement(_stop_time - _start_time, "ns") },
430  { "GPU active", counters },
431  };
432 
433  for(const auto &counter : _core_counters)
434  {
435  for(const auto &core : counter.second.values)
436  {
437  measurements.emplace(counter.second.name + " #" + support::cpp11::to_string(core.first), Measurement(core.second / _scale_factor, _unit + counter.second.unit));
438  }
439  }
440 
441  return measurements;
442 }
443 } // namespace framework
444 } // namespace test
445 } // namespace arm_compute
void stop() override
Stop measuring.
DATA_TYPE product(__global const DATA_TYPE *input)
Calculate product of a vector.
#define ARM_COMPUTE_ERROR(msg)
Print the given message then throw an std::runtime_error.
Definition: Error.h:352
std::string to_string(T &&value)
Convert integer and float values to string.
Generic measurement that stores values as either double or long long int.
Definition: Measurement.h:41
unsigned core_mask
Definition: MaliCounter.cpp:42
std::string id() const override
Identifier for the instrument.
MeasurementsMap measurements() const override
Return the latest measurements.
Copyright (c) 2017-2021 Arm Limited.
MaliCounter(ScaleFactor scale_factor)
Default constructor.
unsigned p_value
Definition: MaliCounter.cpp:41
unsigned gpu_id
Definition: MaliCounter.cpp:39
void end(TokenStream &in, bool &valid)
Definition: MLGOParser.cpp:290
const char * name
void start() override
Start measuring.
std::map< std::string, Measurement > MeasurementsMap
Map of measurements.
Definition: Instrument.h:109
unsigned r_value
Definition: MaliCounter.cpp:40
unsigned mp_count
Definition: MaliCounter.cpp:38