blob: f00b7804b79a22cf2729a854ef69fc513ad5703e [file] [log] [blame]
/*
* Copyright 2022 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "mali/mali_gpu_perf_metrics.h"
#include "mali/mali_gpu_props.h"
const static int kDefaultSleepMicroseconds = 1000000;
void print_general_usage_percentage(int sleep_length) {
int product_id = get_gpu_prop(gpu_prop_product_id);
MaliGpuModel model = get_model_from_product_id(product_id);
int max_freq_khz = get_gpu_prop(gpu_prop_freq_max_khz);
initialize_mali_perf_reader();
int active_cycles_index = 2;
// Most Mali GPUs have a messages_sent and messages_received counter before
// the active_cycles counter, but the T72X does not.
if (model == gpu_model_t72x)
active_cycles_index = 0;
MaliGpuCounter active_cycles = -1;
int counter_idx = -1;
for (int i = 0; i < kCounterBlockSize; i++) {
if (mali_gpu_counter_names[model][0][i]) {
counter_idx++;
if (counter_idx == active_cycles_index) {
active_cycles = (model << 8) | i;
break;
}
}
}
reset_perf_metrics();
usleep(sleep_length);
struct mali_counter_response response = read_perf_metrics(&active_cycles, 1);
printf("%f%% load\n", 100.0 * ((double)response.counter_values[0].values[0]) /
((double)max_freq_khz) / 1000.0 /
((double)sleep_length / 1000000.0));
free_counters(response);
cleanup_mali_perf_reader();
}
void print_all_available_counters(int sleep_length) {
int product_id = get_gpu_prop(gpu_prop_product_id);
MaliGpuModel model = get_model_from_product_id(product_id);
initialize_mali_perf_reader();
int num_counters = 0;
for (int i = 0; i < kNumCounterBlockTypes; i++) {
for (int j = 0; j < kCounterBlockSize; j++) {
if (mali_gpu_counter_names[model][i][j])
num_counters++;
}
}
MaliGpuCounter counters[num_counters];
int counter_idx = 0;
for (int i = 0; i < kNumCounterBlockTypes; i++) {
for (int j = 0; j < kCounterBlockSize; j++) {
if (mali_gpu_counter_names[model][i][j]) {
counters[counter_idx] = (model << 8) | (i << 6) | j;
counter_idx++;
}
}
}
reset_perf_metrics();
usleep(sleep_length);
struct mali_counter_response response =
read_perf_metrics(counters, num_counters);
for (int i = 0; i < response.num_counters; i++) {
for (int j = 0; j < response.counter_values[i].num_values; j++) {
int counter_type = (response.counter_values[i].counter >> 6) & 0x3;
int counter_idx = response.counter_values[i].counter & 0x3F;
printf("%s %d: %d\n",
mali_gpu_counter_names[model][counter_type][counter_idx], j,
response.counter_values[i].values[j]);
}
}
free_counters(response);
cleanup_mali_perf_reader();
}
void print_help() {
printf("mali_stats\n");
printf("A simple program for querying Mali's performance counters.\n");
printf("By default, this program will simply output %% GPU usage.\n");
printf("Usage: mali_stats [-a] [-u sleep_length_in_microseconds]\n");
printf("-u: Set the delay between clearing the counter and reading it.\n");
printf("-a: Dump raw values for every available counter instead of %% ");
printf("usage.\n");
}
int main(int argc, char** argv) {
int sleep_length = kDefaultSleepMicroseconds;
int c;
bool print_all = false;
while ((c = getopt(argc, argv, "ahu:")) != -1) {
switch (c) {
case 'u':
sleep_length = atoi(optarg);
break;
case 'a':
print_all = true;
break;
case 'h':
default:
print_help();
exit(-1);
}
}
if (print_all) {
print_all_available_counters(sleep_length);
} else {
print_general_usage_percentage(sleep_length);
}
}