summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Pitoiset <samuel.pitoiset@gmail.com>2019-02-14 10:31:41 +0100
committerSamuel Pitoiset <samuel.pitoiset@gmail.com>2019-02-18 16:11:41 +0100
commit85ddda03b2c5292fa61412ae9c6e5f9c5ab600c5 (patch)
treea9ef74a0f1a86522698658f77e261cf2850f81fa
parent517d3a873cba9456c6c8712774338d036de3cda4 (diff)
Signed-off-by: Samuel Pitoiset <samuel.pitoiset@gmail.com>
-rw-r--r--run.c119
1 files changed, 116 insertions, 3 deletions
diff --git a/run.c b/run.c
index 9456ec0..e1fc74d 100644
--- a/run.c
+++ b/run.c
@@ -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. */