diff options
author | Samuel Pitoiset <samuel.pitoiset@gmail.com> | 2019-02-14 10:31:41 +0100 |
---|---|---|
committer | Samuel Pitoiset <samuel.pitoiset@gmail.com> | 2019-02-18 16:11:41 +0100 |
commit | 85ddda03b2c5292fa61412ae9c6e5f9c5ab600c5 (patch) | |
tree | a9ef74a0f1a86522698658f77e261cf2850f81fa | |
parent | 517d3a873cba9456c6c8712774338d036de3cda4 (diff) |
wipamdvlk
Signed-off-by: Samuel Pitoiset <samuel.pitoiset@gmail.com>
-rw-r--r-- | run.c | 119 |
1 files changed, 116 insertions, 3 deletions
@@ -42,6 +42,8 @@ #include "serialize.h" +#define MIN2(a, b) ((a) < (b)) ? (a) : (b) + enum vendors { VENDOR_AMD = 0x1002, VENDOR_INTEL = 0x8086 @@ -49,6 +51,13 @@ enum vendors { enum vendors vendor; +enum amd_vendors { + AMD_VENDOR_AMDVLK, + AMD_VENDOR_RADV, +}; + +enum amd_vendors amd_vendor; + #define unlikely(x) __builtin_expect(!!(x), 0) int max_threads; @@ -185,6 +194,69 @@ is_shader_stage_valid(VkDevice device, VkPipeline pipeline, return true; } +static unsigned +amd_get_instr_size(char *instr) +{ + char *token, *saveptr; + uint32_t low, high; + int n; + + /* Extract hexadecimal code of the instruction. */ + token = strtok_r(instr, ";", &saveptr); + token = strtok_r(NULL, ";", &saveptr); + + /* Get hexadecimal size. */ + n = sscanf(token, "%X %X", &low, &high); + assert(n == 1 || n == 2); + + return n * 4; +} + +static unsigned +amd_get_code_size(char *code) +{ + char *token, *saveptr; + unsigned code_size = 0; + + token = strtok_r(code, "\n", &saveptr); + while (token != NULL) { + if (strstr(token, ";")) + code_size += amd_get_instr_size(token); + token = strtok_r(NULL, "\n", &saveptr); + } + + return code_size; +} + +static unsigned +amd_get_max_waves(struct shader_stats *stats) +{ + unsigned max_waves = 8; + + if (stats->num_sgprs) + max_waves = MIN2(max_waves, 800 / stats->num_sgprs); + if (stats->num_vgprs) + max_waves = MIN2(max_waves, 256 / stats->num_vgprs); + + return max_waves; +} + +static int +get_shader_info_stats(VkDevice device, VkPipeline pipeline, + VkShaderStageFlagBits stage, + VkShaderStatisticsInfoAMD *stats) +{ + size_t size = sizeof(*stats); + VkResult result; + + result = vkGetShaderInfo(device, pipeline, stage, + VK_SHADER_INFO_TYPE_STATISTICS_AMD, &size, stats); + if (unlikely(result != VK_SUCCESS)) + return -1; + + return 0; +} + static int get_shader_info(VkDevice device, VkPipeline pipeline, VkShaderStageFlagBits stage, @@ -207,6 +279,8 @@ get_shader_info(VkDevice device, VkPipeline pipeline, if (unlikely(result != VK_SUCCESS)) return -1; + (*shader_info)[size-1] = 0; + return 0; } @@ -373,11 +447,46 @@ create_pipeline(VkDevice device, const char *pipeline_name, if (vendor == VENDOR_AMD) { struct shader_stats stats = {}; - if (unlikely(amd_parse_shader_stats(shader_info, &stats) < 0)) { - fprintf(stderr, "Failed to parse AMD shader statistics!\n"); + + if (amd_vendor == AMD_VENDOR_RADV) { + /* The RADV Vulkan driver computes and dumps shader statistics + * as part of the disassembly code. We only need to parse the + * statistics. + */ + if (unlikely(amd_parse_shader_stats(shader_info, &stats) < 0)) { + fprintf(stderr, "Failed to parse AMD shader statistics!\n"); + goto fail; + } } else { - amd_print_shader_stats(pipeline_name, stage, &stats); + /* Other AMD Vulkan drivers (like AMDVLK), only report the + * number of used VGPRs/SGPRs. Other statistics have to be + * determined directly from the assembly code. This might be + * inacurrate. + */ + VkShaderStatisticsInfoAMD info; + if (unlikely(get_shader_info_stats(device, pipeline, stage, &info) < 0)) { + fprintf(stderr, "Failed to get shader info stats!\n"); + goto fail; + } + + + /* Adjust the number of used VGPRs/SGPRs. */ + stats.num_vgprs = info.resourceUsage.numUsedVgprs; + if (stats.num_vgprs % 4) + stats.num_vgprs = stats.num_vgprs + (4 - stats.num_vgprs % 4); + stats.num_sgprs = info.resourceUsage.numUsedSgprs; + if (stats.num_sgprs % 8) + stats.num_sgprs = stats.num_sgprs + (8 - stats.num_sgprs % 8); + + /* Determine code size from the assembly. */ + stats.code_size = amd_get_code_size(shader_info); + + /* Determine number of waves from used VGPRs/SGPRs. */ + stats.max_waves = amd_get_max_waves(&stats); } + + /* Output shader statistics for this stage. */ + amd_print_shader_stats(pipeline_name, stage, &stats); } else { char *line = NULL; @@ -528,6 +637,10 @@ int main(int argc, char **argv) VkPhysicalDeviceProperties device_properties; vkGetPhysicalDeviceProperties(physical_devices[0], &device_properties); vendor = device_properties.vendorID; + if (vendor == VENDOR_AMD && + strstr(device_properties.deviceName, "RADV")) { + amd_vendor = AMD_VENDOR_RADV; + } fprintf(stderr, "GPU: %s\n", device_properties.deviceName); /* Get queue properties. */ |