vulkan-shader-profiler is a perfetto-based Vulkan shader profiler using the layering capability of the Vulkan-Loader.
It allows you to visualize Vulkan application execution using Perfetto, providing detailed information about compute shaders to help identify performance bottlenecks, and associates Vulkan SPIR-V source code with the trace events.
Using the vulkan-shader-profiler-extractor and vulkan-shader-profiler-runner, it is also possible to extract a specific dispatch from the trace (using the dispatchId debug information from the trace), and replay it with the runner.
vulkan-shader-profiler is licensed under the terms of the Apache 2.0 license.
This is not an officially supported Google product. This project is not eligible for the Google Open Source Software Vulnerability Rewards Program.
- Vulkan-Loader
- Vulkan-Headers
- SPIRV-Headers
- SPIRV-Tools
- perfetto
- A working Vulkan implementation/driver.
vulkan-shader-profiler uses CMake for its build system.
To compile it, please run:
cmake -B <build_dir> -S . \
-DPERFETTO_SDK_PATH=<path-to-perfetto-sdk> \
-DPERFETTO_TRACE_PROCESSOR_LIB=<path-to-libtrace_processor.a> \
-DPERFETTO_INTERNAL_INCLUDE_PATH=<path-to-perfetto-include> \
-DSPIRV_TOOLS_SOURCE_PATH=<path-to-spirv-tools-source-dir> \
-DSPIRV_TOOLS_BUILD_PATH=<path-to-spirv-tools-build-dir>
cmake --build <build_dir>For real-life examples, refer to:
- ChromeOS ebuild
- GitHub presubmit configuration
- Required:
PERFETTO_SDK_PATH: Path to perfetto SDK (looks forperfetto.ccandperfetto.hin this directory).PERFETTO_TRACE_PROCESSOR_LIB: Path tolibtrace_processor.aproduced by a Perfetto build.PERFETTO_INTERNAL_INCLUDE_PATH: Path to Perfetto internal include directory (<perfetto>/include).SPIRV_TOOLS_SOURCE_PATH: Path to SPIRV-Tools source directory.SPIRV_TOOLS_BUILD_PATH: Path to where SPIRV-Tools is built.
- Optional:
PERFETTO_LIBRARY: Name of a Perfetto library already available (avoids compilingperfetto.cc).BACKEND: Perfetto backend to use:InProcess(default): The application generates the traces. Build options and environment variables control trace size and destination.System: Uses the system'straceddaemon.
TRACE_MAX_SIZE(InProcess only): Max trace size in KB. Can be overridden at runtime viaVKSP_TRACE_MAX_SIZE(Default:1024).TRACE_DEST(InProcess only): Default trace output file. Can be overridden at runtime viaVKSP_TRACE_DEST(Default:vulkan-shader-profiler.trace).
For Android, only the Layer and the Runner are supported for device execution.
- Clone the repository into your AOSP tree under
external/vulkan-shader-profiler. - Compile using Soong:
m libVkLayer_shader_profiler vulkan-shader-profiler-runner
To run an application with the profiler layer enabled, ensure the following:
- The
Vulkan-Loadercan find the manifest inmanifest/vulkan-shader-profiler.json. Set this using:export VK_ADD_LAYER_PATH=<path-to-vulkan-shader-profiler-manifest-dir>
- Enable the layer:
export VK_LOADER_LAYERS_ENABLE="VK_LAYER_SHADER_PROFILER"
You can also extract memory contents of buffers and images used by a specific dispatch. This requires a first run to generate the trace, followed by a second run with VKSP_EXTRACT_BUFFERS_FROM=<trace.spvasm> set. This generates a <trace.spvasm.buffers> file for the runner. Buffers can also be extracted individually by setting VKSP_EXTRACT_MULTIPLE_BUFFERS=1 and merged using vulkan-shader-profiler-merge-buffers (see test/test-buffers.sh for an example).
Make sure you have emerged and deployed the vulkan-shader-profiler. Then run the application using vulkan-shader-profiler.sh, which sets up the necessary environment variables.
- Push the library to the device:
adb push $OUT/system/lib64/libVkLayer_shader_profiler.so /data/local/debug/vulkan/ - Enable the layer:
adb shell setprop debug.vulkan.layers VK_LAYER_SHADER_PROFILER
Once traces are generated, you can view them using the Perfetto trace viewer.
You can extract a single dispatch from a generated trace using the dispatchId found in the trace:
vulkan-shader-profiler-extractor -i <input_trace> -o <output_file> -d <dispatchId> [OPTIONS]-i: Path to the trace generated by the layer.-o: Output path (readable SPIR-V text by default).-d: ThedispatchIdto extract.-b: Output binary SPIR-V instead of text.-s: Path to a shader file to use instead of the trace (see Large Shaders).-v: Enable verbose debug mode.
Only programs extracted with vulkan-shader-profiler-extractor can be run with the runner:
vulkan-shader-profiler-runner -i <input> [OPTIONS]-i: Path to the extracted SPIR-V program.-b: Path to the associated buffers file (generated viaVKSP_EXTRACT_BUFFERS_FROM).-c: Disable counters to run without overhead.-e: Targetspv_target_envfor text input conversion (default:vulkan1.3).-n: Number of hot runs.-m: Number of cold runs before benchmarking.-o: Descriptor set index and binding of a buffer to dump (e.g.,1.2).-p: Force Vulkan queue global priority (0: low, 1: medium, 2: high, 3: realtime).-v: Enable verbose debug mode.
You can profile specific sections of the program by adding non-semantic instructions:
%vksp = OpExtInstImport "NonSemantic.VkspReflection.4"
...
%ct = OpExtInst %void %vksp StartCounter "my_section"
...
%un = OpExtInst %void %vksp StopCounter %ctThe runner will output the percentage of time spent in that section.
vulkan-shader-profiler intercepts key Vulkan APIs to track execution and resources.
Every intercepted call also generates a trace event for the function itself.
vkGetDeviceQueue: Creates internal structures to trace everything executed on this queue.vkAllocateCommandBuffers: Creates internal structures for the command buffer.vkFreeCommandBuffers: Cleans up internal structures for the command buffer.vkBeginCommandBuffer: Initializes internal structures for command buffer recording.vkQueueSubmit: Modifies submit information to add a timeline semaphore for tracking submission completion, and spawns a background thread to process completed query results.vkCmdDispatch: Records dispatch details to associate with the trace event when executed.vkCmdBindPipeline: Tracks the active pipeline for the command buffer.vkCreateComputePipelines: Associates the pipeline with its compute shader stage.vkCreateShaderModule: Disassembles the SPIR-V shader and writes it into the Perfetto trace.
These calls are tracked to capture resource state for the extractor:
vkUpdateDescriptorSetsvkCmdBindDescriptorSetsvkCmdPushConstantsvkAllocateMemoryvkCreateBuffervkBindBufferMemoryvkCreateImagevkCreateImageViewvkBindImageMemoryvkCreateSampler
The layer calls these APIs internally to perform timing and buffer extraction:
- Timing & Synchronization:
vkCreateSemaphore,vkDestroySemaphore,vkWaitSemaphores: Used to track workload completion on the GPU.vkCreateQueryPool,vkDestroyQueryPool,vkGetQueryPoolResults,vkCmdResetQueryPool: Used to allocate and retrieve timestamps.vkCmdWriteTimestamp: Injected into command buffers to mark start/end times.vkGetCalibratedTimestampsEXT: Used to align GPU timestamps with the host CPU timeline.vkGetPhysicalDeviceProperties: Used to retrievetimestampPeriodto convert ticks to nanoseconds.
- Buffer/Image Extraction:
vkCmdPipelineBarrier,vkCmdCopyBuffer,vkCmdCopyImage: Used to copy resource data to host-visible staging memory.vkMapMemory,vkUnmapMemory: Used to read staging memory on the host.vkGetImageMemoryRequirements,vkGetBufferMemoryRequirements: Used to allocate appropriate staging memory.vkDestroyImage,vkDestroyBuffer,vkFreeMemory: Used to clean up staging resources.vkGetPhysicalDeviceMemoryProperties: Used to find suitable memory types for staging resources.
Large shader code might get truncated or missing in Perfetto traces.
Workaround:
- Run with
VKSP_SHADER_DIR=<path>set to an existing directory. The layer will dump binary.spvfiles there. - Use the
-soption withvulkan-shader-profiler-extractorto specify the dumped shader file instead of retrieving it from the trace.