Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 16 additions & 54 deletions layersvt/device_memory_report/device_memory_report_perfetto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,63 +32,25 @@ void InitializeDeviceMemoryReportPerfetto() {
});
}

namespace {
static const std::unordered_map<std::string_view, perfetto::CounterTrack> kStaticTracks = {
// App usage tracks
{"vulkan.mem.app.usage.staging_transfer", perfetto::CounterTrack("vulkan.mem.app.usage.staging_transfer").set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES)},
{"vulkan.mem.app.usage.ray_tracing", perfetto::CounterTrack("vulkan.mem.app.usage.ray_tracing").set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES)},
{"vulkan.mem.app.usage.indirect_gpu_driven", perfetto::CounterTrack("vulkan.mem.app.usage.indirect_gpu_driven").set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES)},
{"vulkan.mem.app.usage.compute_storage", perfetto::CounterTrack("vulkan.mem.app.usage.compute_storage").set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES)},
{"vulkan.mem.app.usage.uniform_constants", perfetto::CounterTrack("vulkan.mem.app.usage.uniform_constants").set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES)},
{"vulkan.mem.app.usage.geometry_mesh", perfetto::CounterTrack("vulkan.mem.app.usage.geometry_mesh").set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES)},
{"vulkan.mem.app.usage.transform_feedback", perfetto::CounterTrack("vulkan.mem.app.usage.transform_feedback").set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES)},
{"vulkan.mem.app.usage.general_buffer", perfetto::CounterTrack("vulkan.mem.app.usage.general_buffer").set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES)},
{"vulkan.mem.app.usage.transient_memoryless", perfetto::CounterTrack("vulkan.mem.app.usage.transient_memoryless").set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES)},
{"vulkan.mem.app.usage.storage_compute_image", perfetto::CounterTrack("vulkan.mem.app.usage.storage_compute_image").set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES)},
{"vulkan.mem.app.usage.depth_stencil_target", perfetto::CounterTrack("vulkan.mem.app.usage.depth_stencil_target").set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES)},
{"vulkan.mem.app.usage.color_render_target", perfetto::CounterTrack("vulkan.mem.app.usage.color_render_target").set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES)},
{"vulkan.mem.app.usage.static_texture", perfetto::CounterTrack("vulkan.mem.app.usage.static_texture").set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES)},
{"vulkan.mem.app.usage.general_image", perfetto::CounterTrack("vulkan.mem.app.usage.general_image").set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES)},
{"vulkan.mem.app.usage.unbound_memory", perfetto::CounterTrack("vulkan.mem.app.usage.unbound_memory").set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES)},

// Driver usage tracks
{"vulkan.mem.driver.usage.staging_transfer", perfetto::CounterTrack("vulkan.mem.driver.usage.staging_transfer").set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES)},
{"vulkan.mem.driver.usage.ray_tracing", perfetto::CounterTrack("vulkan.mem.driver.usage.ray_tracing").set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES)},
{"vulkan.mem.driver.usage.indirect_gpu_driven", perfetto::CounterTrack("vulkan.mem.driver.usage.indirect_gpu_driven").set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES)},
{"vulkan.mem.driver.usage.compute_storage", perfetto::CounterTrack("vulkan.mem.driver.usage.compute_storage").set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES)},
{"vulkan.mem.driver.usage.uniform_constants", perfetto::CounterTrack("vulkan.mem.driver.usage.uniform_constants").set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES)},
{"vulkan.mem.driver.usage.geometry_mesh", perfetto::CounterTrack("vulkan.mem.driver.usage.geometry_mesh").set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES)},
{"vulkan.mem.driver.usage.transform_feedback", perfetto::CounterTrack("vulkan.mem.driver.usage.transform_feedback").set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES)},
{"vulkan.mem.driver.usage.general_buffer", perfetto::CounterTrack("vulkan.mem.driver.usage.general_buffer").set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES)},
{"vulkan.mem.driver.usage.transient_memoryless", perfetto::CounterTrack("vulkan.mem.driver.usage.transient_memoryless").set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES)},
{"vulkan.mem.driver.usage.storage_compute_image", perfetto::CounterTrack("vulkan.mem.driver.usage.storage_compute_image").set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES)},
{"vulkan.mem.driver.usage.depth_stencil_target", perfetto::CounterTrack("vulkan.mem.driver.usage.depth_stencil_target").set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES)},
{"vulkan.mem.driver.usage.color_render_target", perfetto::CounterTrack("vulkan.mem.driver.usage.color_render_target").set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES)},
{"vulkan.mem.driver.usage.static_texture", perfetto::CounterTrack("vulkan.mem.driver.usage.static_texture").set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES)},
{"vulkan.mem.driver.usage.general_image", perfetto::CounterTrack("vulkan.mem.driver.usage.general_image").set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES)},
{"vulkan.mem.driver.usage.unbound_memory", perfetto::CounterTrack("vulkan.mem.driver.usage.unbound_memory").set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES)},
};
} // namespace

perfetto::CounterTrack GetCounterTrack(std::string_view name) {
auto it = kStaticTracks.find(name);
if (it != kStaticTracks.end()) {
static std::mutex tracks_mutex;
// Declare track_names first so LIFO static destruction destroys tracks before the strings it views.
static std::unordered_set<std::string> track_names;
static std::unordered_map<std::string_view, perfetto::CounterTrack> tracks;
std::lock_guard<std::mutex> lock(tracks_mutex);

auto it = tracks.find(name);
if (it != tracks.end()) {
return it->second;
}
static std::mutex dynamic_mutex;
static std::unordered_map<std::string, perfetto::CounterTrack> dynamic_tracks;
static std::unordered_set<std::string> dynamic_names;
std::lock_guard<std::mutex> lock(dynamic_mutex);
auto dyn_it = dynamic_tracks.find(std::string(name));
if (dyn_it != dynamic_tracks.end()) {
return dyn_it->second;
}
auto name_it = dynamic_names.insert(std::string(name)).first;
perfetto::CounterTrack track = perfetto::CounterTrack(perfetto::DynamicString(name_it->c_str()))

// CounterTrack captures ProcessTrack::Current().uuid at construction time; ensure tracing is
// initialized before constructing the first track so it isn't parented to the null/global track.
InitializeDeviceMemoryReportPerfetto();

auto name_it = track_names.emplace(name).first;
perfetto::CounterTrack track = perfetto::CounterTrack(perfetto::DynamicString(*name_it))
.set_unit(perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES);
dynamic_tracks.emplace(
std::piecewise_construct,
std::forward_as_tuple(*name_it),
std::forward_as_tuple(track));
tracks.emplace(*name_it, track);
return track;
}
Comment thread
jimblacklercorp marked this conversation as resolved.
59 changes: 59 additions & 0 deletions layersvt/test/test_devicememoryreport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,65 @@ TEST_F(DeviceMemoryReportTests, StaticCounterTrackLookup) {
EXPECT_EQ(dynamic_track_again.Serialize().counter().unit(), perfetto::protos::gen::CounterDescriptor::UNIT_SIZE_BYTES);
}

TEST_F(DeviceMemoryReportTests, CounterTracksAreScopedToProcessTrack) {
TEST_DESCRIPTION(
"Test that counter tracks are parented to the process track, so Perfetto scopes them under the traced "
"application instead of emitting them as global tracks");

InitializeDeviceMemoryReportPerfetto();

// Perfetto only assigns a process uuid once tracing has been initialized. Tracks created before that (for
// example during static initialization) are permanently parented to the null/global track.
const uint64_t process_uuid = perfetto::ProcessTrack::Current().uuid;
ASSERT_NE(process_uuid, 0u) << "Perfetto tracing was not initialized";

const char* kTrackNames[] = {
"vulkan.mem.app.usage.color_render_target",
"vulkan.mem.app.usage.unbound_memory",
"vulkan.mem.driver.usage.static_texture",
"vulkan.mem.driver.usage.unbound_memory",
"vulkan.mem.app.usage.brand_new_category",
};

for (const char* name : kTrackNames) {
perfetto::CounterTrack track = GetCounterTrack(name);

EXPECT_NE(track.uuid, 0u) << "track " << name;
EXPECT_EQ(track.parent_uuid, process_uuid) << "track " << name << " is not scoped to the process track";

// The uuid must match what Perfetto derives for a process-scoped track of the same name.
EXPECT_EQ(track.uuid, perfetto::CounterTrack(perfetto::DynamicString(name)).uuid) << "track " << name;

const perfetto::protos::gen::TrackDescriptor descriptor = track.Serialize();
EXPECT_EQ(descriptor.uuid(), track.uuid) << "track " << name;
EXPECT_EQ(descriptor.parent_uuid(), process_uuid) << "track " << name;
EXPECT_EQ(descriptor.counter().unit(), perfetto::protos::gen::CounterDescriptor::UNIT_SIZE_BYTES)
<< "track " << name;
}
}

TEST_F(DeviceMemoryReportTests, GetCounterTrackInitializesTracing) {
TEST_DESCRIPTION("Test that GetCounterTrack initializes Perfetto itself, so tracks always have process context");

// Force fork+execve so the child starts with an uninitialized process_uuid rather than
// inheriting static state already initialized by earlier tests in this binary.
GTEST_FLAG_SET(death_test_style, "threadsafe");

EXPECT_EXIT(
{
if (perfetto::ProcessTrack::Current().uuid != 0u) {
exit(1);
}
perfetto::CounterTrack track = GetCounterTrack("vulkan.mem.app.usage.general_image");
const uint64_t process_uuid = perfetto::ProcessTrack::Current().uuid;
if (process_uuid == 0u || track.parent_uuid != process_uuid) {
exit(2);
}
exit(0);
},
::testing::ExitedWithCode(0), "");
}

TEST_F(DeviceMemoryReportTests, DriverVsAppUnboundMemoryAttribution) {
TEST_DESCRIPTION("Test that application unbound memory is not misclassified when object handle matches an existing resource handle");

Expand Down
Loading