mirror of
https://github.com/wolfpld/tracy.git
synced 2026-10-23 01:00:54 +00:00
CUDACtx's constructor writes GpuNewContext directly through QueueSerialFinish(), unlike every other GPU backend (Vulkan, OpenGL, D3D11/12, Metal, WebGPU, Rocprof), which all defer it via GetProfiler().DeferItem() so it survives on-demand's per-connection queue clear. A profiler connecting any time after the CUDA context is created (in practice: any time after process start) never receives GpuNewContext. The GpuContextName message that Name() sends right after (already correctly deferred) then crashes the server's Worker::ProcessGpuContextName with an unregistered context id (assert(ctx) fails; undefined behavior in release builds). Same fix already applied to the Rocprof backend in #1336. Fixes #1171. Includes a repro test under tests/cuda/repro/on_demand/, mirroring the structure #1336 added for Rocprof: a minimal CUDA program that creates an on-demand context (repro.cu/CMakeLists.txt), and a check_gpu_zones tool that loads the resulting .tracy file and verifies the GPU context was named and populated with zones. Verified locally: unpatched tracy-capture crashes on the first connection attempt; patched, three consecutive connect/disconnect cycles all succeed and check_gpu_zones reports a named context with recorded zones.
59 lines
1.8 KiB
C++
59 lines
1.8 KiB
C++
// Loads a .tracy file and prints, for each GPU context, whether it is
|
|
// named and how many GPU zones it recorded. Used to verify that a
|
|
// late-connecting client correctly received the deferred GpuNewContext
|
|
// (and, downstream, actual GPU zone data) rather than the connection
|
|
// having crashed the server before any capture was possible.
|
|
//
|
|
// Usage: ./check_gpu_zones trace.tracy
|
|
// Expected output: "GPU context 0: line_scan_processing_cuda, 100 zones"
|
|
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include "server/TracyFileRead.hpp"
|
|
#include "server/TracyWorker.hpp"
|
|
|
|
int main( int argc, char** argv )
|
|
{
|
|
if( argc != 2 )
|
|
{
|
|
fprintf( stderr, "Usage: %s <trace.tracy>\n", argv[0] );
|
|
return 1;
|
|
}
|
|
|
|
try
|
|
{
|
|
auto f = std::unique_ptr<tracy::FileRead>( tracy::FileRead::Open( argv[1] ) );
|
|
if( !f )
|
|
{
|
|
fprintf( stderr, "Cannot open %s\n", argv[1] );
|
|
return 1;
|
|
}
|
|
|
|
tracy::Worker worker( *f, tracy::EventType::None, false );
|
|
|
|
const auto& gpuData = worker.GetGpuData();
|
|
if( gpuData.empty() )
|
|
{
|
|
printf( "No GPU contexts found.\n" );
|
|
return 2;
|
|
}
|
|
|
|
bool all_good = true;
|
|
for( size_t i = 0; i < gpuData.size(); i++ )
|
|
{
|
|
const auto& ctx = gpuData[i];
|
|
const bool has_name = ctx->name.Active() && worker.GetString( ctx->name )[0] != '\0';
|
|
const char* name = has_name ? worker.GetString( ctx->name ) : "(unnamed)";
|
|
printf( "GPU context %zu: %s, %lu zones\n", i, name, (unsigned long)ctx->count );
|
|
if( !has_name || ctx->count == 0 ) all_good = false;
|
|
}
|
|
|
|
return all_good ? 0 : 2;
|
|
}
|
|
catch( const std::exception& e )
|
|
{
|
|
fprintf( stderr, "Error: %s\n", e.what() );
|
|
return 1;
|
|
}
|
|
}
|