This commit is contained in:
xsl
2025-09-04 10:54:47 +08:00
commit 6bc8f61b18
1808 changed files with 208268 additions and 0 deletions
+274
View File
@@ -0,0 +1,274 @@
/* Copyright (c) 2018-2025, Arm Limited and Contributors
* Copyright (c) 2020-2025, Broadcom Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 the "License";
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "hwcpipe_stats_provider.h"
namespace
{
const char *get_product_family_name(hwcpipe::device::gpu_family f)
{
using gpu_family = hwcpipe::device::gpu_family;
switch (f)
{
case gpu_family::bifrost:
return "Bifrost";
case gpu_family::midgard:
return "Midgard";
case gpu_family::valhall:
return "Valhall";
default:
return "Unknown";
}
}
} // namespace
namespace vkb
{
HWCPipeStatsProvider::HWCPipeStatsProvider(std::set<StatIndex> &requested_stats)
{
// Mapping of stats to their hwcpipe availability
// clang-format off
StatDataMap hwcpipe_stats = {
{StatIndex::gpu_cycles, {hwcpipe_counter::MaliGPUActiveCy}},
{StatIndex::gpu_vertex_cycles, {hwcpipe_counter::MaliNonFragQueueActiveCy, {MaliNonFragActiveCy, MaliBinningQueueActiveCy} }},
{StatIndex::gpu_load_store_cycles, {hwcpipe_counter::MaliLSIssueCy}},
{StatIndex::gpu_tiles, {hwcpipe_counter::MaliFragTile}},
{StatIndex::gpu_killed_tiles, {hwcpipe_counter::MaliFragTileKill}},
{StatIndex::gpu_fragment_cycles, {hwcpipe_counter::MaliFragQueueActiveCy, {MaliFragActiveCy, MaliMainQueueActiveCy}}},
{StatIndex::gpu_fragment_jobs, {hwcpipe_counter::MaliFragQueueJob, {MaliMainQueueJob}}},
{StatIndex::gpu_ext_reads, {hwcpipe_counter::MaliExtBusRdBt}},
{StatIndex::gpu_ext_writes, {hwcpipe_counter::MaliExtBusWrBt}},
{StatIndex::gpu_ext_read_stalls, {hwcpipe_counter::MaliExtBusRdStallCy}},
{StatIndex::gpu_ext_write_stalls, {hwcpipe_counter::MaliExtBusWrStallCy}},
{StatIndex::gpu_ext_read_bytes, {hwcpipe_counter::MaliExtBusRdBy}},
{StatIndex::gpu_ext_write_bytes, {hwcpipe_counter::MaliExtBusWrBy}},
{StatIndex::gpu_tex_cycles, {hwcpipe_counter::MaliTexIssueCy}}};
// clang-format on
// Detect all GPUs & print some info
for (const auto &gpu : hwcpipe::find_gpus())
{
LOGI("HWCPipe: ------------------------------------------------------------");
LOGI("HWCPipe: GPU Device {}:", gpu.get_device_number());
LOGI("HWCPipe: ------------------------------------------------------------");
LOGI("HWCPipe: Product Family: {}", get_product_family_name(gpu.get_gpu_family()));
LOGI("HWCPipe: Number of Cores: {}", gpu.num_shader_cores());
LOGI("HWCPipe: Bus Width: {}", gpu.bus_width());
}
// Probe device 0 (i.e. /dev/mali0)
auto gpu = hwcpipe::gpu(0);
if (!gpu)
{
LOGE("HWCPipe: Mali GPU device 0 is missing");
}
auto config = hwcpipe::sampler_config(gpu);
auto counter_db = hwcpipe::counter_database{};
std::error_code ec;
for (const auto &stat : requested_stats)
{
auto it = hwcpipe_stats.find(stat);
if (it != hwcpipe_stats.end())
{
hwcpipe::counter_metadata meta;
auto ec = counter_db.describe_counter(it->second.counter, meta);
if (ec)
{
LOGE("HWCPipe: unknown counter");
}
ec = config.add_counter(it->second.counter);
if (ec)
{
// Some counters have changed in recent devices
auto &fallback_list = it->second.fallback_list;
if (!fallback_list.empty())
{
for (const auto &fallback : fallback_list)
{
ec = counter_db.describe_counter(fallback, meta);
ec = config.add_counter(fallback);
if (!ec)
{
// Replace counter with available alternative
it->second.counter = fallback;
break;
}
}
}
}
if (ec)
{
LOGE("HWCPipe: '{}' counter not supported by this GPU.", meta.name);
}
else
{
stat_data[stat] = hwcpipe_stats[stat];
LOGI("HWCPipe: enabled '{}' counter", meta.name);
}
}
}
// Remove any supported stats from the requested set.
// Subsequent providers will then only look for things that aren't already supported.
for (const auto &iter : stat_data)
{
requested_stats.erase(iter.first);
}
stat_data_count = stat_data.size();
sampler = std::make_unique<hwcpipe::sampler<>>(config);
if (stat_data_count > 0)
{
ec = sampler->start_sampling();
if (ec)
{
LOGE("HWCPipe: {}", ec.message());
}
}
}
HWCPipeStatsProvider::~HWCPipeStatsProvider()
{
std::error_code ec;
if (stat_data_count > 0)
{
ec = sampler->stop_sampling();
if (ec)
{
LOGE("HWCPipe: {}", ec.message());
}
}
}
bool HWCPipeStatsProvider::is_available(StatIndex index) const
{
return stat_data.find(index) != stat_data.end();
}
const StatGraphData &HWCPipeStatsProvider::get_graph_data(StatIndex index) const
{
assert(is_available(index) && "HWCPipeStatsProvider::get_graph_data() called with invalid StatIndex");
static StatGraphData vertex_compute_cycles{"Vertex Compute Cycles", "{:4.1f} M/s", static_cast<float>(1e-6)};
// HWCPipe reports combined vertex/compute cycles (which is Arm specific)
// Ensure we report graph with the correct name when asked for vertex cycles
if (index == StatIndex::gpu_vertex_cycles)
{
return vertex_compute_cycles;
}
return default_graph_map[index];
}
static double get_gpu_counter_value(const hwcpipe::counter_sample &sample)
{
switch (sample.type)
{
case hwcpipe::counter_sample::type::uint64:
return sample.value.uint64;
case hwcpipe::counter_sample::type::float64:
return sample.value.float64;
default:
return 0.0;
}
}
StatsProvider::Counters HWCPipeStatsProvider::sample(float delta_time)
{
Counters res;
if (stat_data_count < 1)
{
return res;
}
std::error_code ec;
ec = sampler->sample_now();
if (ec)
{
LOGE("HWCPipe: {}", ec.message());
}
else
{
// Map from hwcpipe measurement to our sample result for each counter
for (auto iter : stat_data)
{
StatIndex index = iter.first;
const StatData &data = iter.second;
hwcpipe::counter_sample sample;
ec = sampler->get_counter_value(data.counter, sample);
if (ec)
{
LOGE("HWCPipe: {}", ec.message());
continue;
}
auto d = get_gpu_counter_value(sample);
if (data.scaling == StatScaling::ByDeltaTime && delta_time != 0.0f)
{
d /= delta_time;
}
else if (data.scaling == StatScaling::ByCounter)
{
ec = sampler->get_counter_value(data.divisor, sample);
if (ec)
{
LOGE("HWCPipe: {}", ec.message());
continue;
}
double divisor = get_gpu_counter_value(sample);
if (divisor != 0.0)
{
d /= divisor;
}
else
{
d = 0.0;
}
}
res[index].result = d;
}
}
return res;
}
StatsProvider::Counters HWCPipeStatsProvider::continuous_sample(float delta_time)
{
return sample(delta_time);
}
} // namespace vkb