[Mesa-dev] [PATCH 2/2] vkpipeline-db: add support for anv
Samuel Pitoiset
samuel.pitoiset at gmail.com
Tue Jun 12 12:38:45 UTC 2018
Acked-by: Samuel Pitoiset <samuel.pitoiset at gmail.com>
On 06/12/2018 07:05 AM, Timothy Arceri wrote:
> From: Timothy Arceri <tarceri at localhost.localdomain>
>
> ---
> anv-report.py | 191 ++++++++++++++++++++++++++++++++++++++++++++++++++
> run.c | 75 +++++++++++++-------
> 2 files changed, 239 insertions(+), 27 deletions(-)
> create mode 100755 anv-report.py
>
> diff --git a/anv-report.py b/anv-report.py
> new file mode 100755
> index 0000000..b306220
> --- /dev/null
> +++ b/anv-report.py
> @@ -0,0 +1,191 @@
> +#!/usr/bin/env python3
> +
> +import re
> +import argparse
> +
> +
> +def get_results(filename):
> + file = open(filename, "r")
> + lines = file.read().split('\n')
> +
> + results = {}
> +
> + re_match = re.compile(r"(\S+) - (\S+ \S+) shader: (\S*) inst, (\S*) loops, (\S*) cycles, (\S*):(\S*) spills:fills")
> + for line in lines:
> + match = re.search(re_match, line)
> + if match is None:
> + continue
> +
> + groups = match.groups()
> + inst_count = int(groups[2])
> + loop_count = int(groups[3])
> + cycle_count = int(groups[4])
> + spill_count = int(groups[5])
> + fill_count = int(groups[6])
> + if inst_count != 0:
> + results[(groups[0], groups[1])] = {
> + "instructions": inst_count,
> + "spills": spill_count,
> + "fills": fill_count,
> + "cycles": cycle_count,
> + "loops": loop_count
> + }
> +
> + return results
> +
> +
> +def format_percent(frac):
> + """Converts a factional value (typically 0.0 to 1.0) to a string as a percentage"""
> + if abs(frac) > 0.0 and abs(frac) < 0.0001:
> + return "<.01%"
> + else:
> + return "{:.2f}%".format(frac * 100)
> +
> +
> +def get_delta(b, a):
> + if b != 0 and a != 0:
> + frac = float(a) / float(b) - 1.0
> + return ' ({})'.format(format_percent(frac))
> + else:
> + return ''
> +
> +
> +def change(b, a):
> + return str(b) + " -> " + str(a) + get_delta(b, a)
> +
> +
> +def get_result_string(p, b, a):
> + p = p + ": "
> + while len(p) < 50:
> + p = p + ' '
> + return p + change(b, a)
> +
> +def split_list(string):
> + return string.split(",")
> +
> +def main():
> + parser = argparse.ArgumentParser()
> + parser.add_argument("--measurements", "-m", type=split_list,
> + default=["instructions", "cycles", "loops", "spills", "fills"],
> + help="comma-separated list of measurements to report")
> + parser.add_argument("--summary-only", "-s", action="store_true", default=False,
> + help="do not show the per-shader helped / hurt data")
> + parser.add_argument("--changes-only", "-c", action="store_true", default=False,
> + help="only show measurements that have changes")
> + parser.add_argument("before", type=get_results, help="the output of the original code")
> + parser.add_argument("after", type=get_results, help="the output of the new code")
> + args = parser.parse_args()
> +
> + total_before = {}
> + total_after = {}
> + affected_before = {}
> + affected_after = {}
> + num_hurt = {}
> + num_helped = {}
> +
> + for m in args.measurements:
> + total_before[m] = 0
> + total_after[m] = 0
> + affected_before[m] = 0
> + affected_after[m] = 0
> +
> + helped = []
> + hurt = []
> + for p in args.before:
> + before_count = args.before[p][m]
> +
> + if args.after.get(p) is None:
> + continue
> +
> + # If the number of loops changed, then we may have unrolled some
> + # loops, in which case other measurements will be misleading.
> + if m != "loops" and args.before[p]["loops"] != args.after[p]["loops"]:
> + continue
> +
> + after_count = args.after[p][m]
> +
> + total_before[m] += before_count
> + total_after[m] += after_count
> +
> + if before_count != after_count:
> + affected_before[m] += before_count
> + affected_after[m] += after_count
> +
> + if after_count > before_count:
> + hurt.append(p)
> + else:
> + helped.append(p)
> +
> + if not args.summary_only:
> + helped.sort(
> + key=lambda k: args.after[k][m] if args.before[k][m] == 0 else float(args.before[k][m] - args.after[k][m]) / args.before[k][m])
> + for p in helped:
> + namestr = p[0] + " " + p[1]
> + print(m + " helped: " + get_result_string(
> + namestr, args.before[p][m], args.after[p][m]))
> + if helped:
> + print("")
> +
> + hurt.sort(
> + key=lambda k: args.after[k][m] if args.before[k][m] == 0 else float(args.after[k][m] - args.before[k][m]) / args.before[k][m])
> + for p in hurt:
> + namestr = p[0] + " " + p[1]
> + print(m + " HURT: " + get_result_string(
> + namestr, args.before[p][m], args.after[p][m]))
> + if hurt:
> + print("")
> +
> + num_helped[m] = len(helped)
> + num_hurt[m] = len(hurt)
> +
> +
> + lost = []
> + gained = []
> +
> + for p in args.before:
> + if args.after.get(p) is None:
> + lost.append(p[0] + " " + p[1])
> +
> + for p in args.after:
> + if args.before.get(p) is None:
> + gained.append(p[0] + " " + p[1])
> +
> + if not args.summary_only:
> + lost.sort()
> + for p in lost:
> + print("LOST: " + p)
> + if lost:
> + print("")
> +
> + gained.sort()
> + for p in gained:
> + print("GAINED: " + p)
> + if gained:
> + print("")
> +
> + any_helped_or_hurt = False
> + for m in args.measurements:
> + if num_helped[m] > 0 or num_hurt[m] > 0:
> + any_helped_or_hurt = True
> +
> + if num_helped[m] > 0 or num_hurt[m] > 0 or not args.changes_only:
> + print("total {0} in shared programs: {1}\n"
> + "{0} in affected programs: {2}\n"
> + "helped: {3}\n"
> + "HURT: {4}\n".format(
> + m,
> + change(total_before[m], total_after[m]),
> + change(affected_before[m], affected_after[m]),
> + num_helped[m],
> + num_hurt[m]))
> +
> +
> + if lost or gained or not args.changes_only:
> + print("LOST: " + str(len(lost)))
> + print("GAINED: " + str(len(gained)))
> + else:
> + if not any_helped_or_hurt:
> + print("No changes.")
> +
> +if __name__ == "__main__":
> + main()
> diff --git a/run.c b/run.c
> index a962887..25b9e44 100644
> --- a/run.c
> +++ b/run.c
> @@ -42,6 +42,13 @@
>
> #include "serialize.h"
>
> +enum vendors {
> + VENDOR_AMD = 0x1002,
> + VENDOR_INTEL = 0x8086
> +};
> +
> +enum vendors vendor;
> +
> #define unlikely(x) __builtin_expect(!!(x), 0)
>
> int max_threads;
> @@ -130,7 +137,7 @@ struct shader_stats
> return -1;
>
> static int
> -parse_shader_stats(char *buf, struct shader_stats *stats)
> +amd_parse_shader_stats(char *buf, struct shader_stats *stats)
> {
> char *line;
> char *saveptr;
> @@ -179,39 +186,28 @@ is_shader_stage_valid(VkDevice device, VkPipeline pipeline,
> }
>
> static int
> -get_shader_stats(VkDevice device, VkPipeline pipeline,
> - VkShaderStageFlagBits stage,
> - struct shader_stats *stats)
> +get_shader_info(VkDevice device, VkPipeline pipeline,
> + VkShaderStageFlagBits stage,
> + char **shader_info)
> {
> VkResult result;
> size_t size;
> - char *buf;
> - int ret = 0;
>
> result = vkGetShaderInfo(device, pipeline, stage,
> VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD, &size, NULL);
> if (unlikely(result != VK_SUCCESS))
> return -1;
>
> - buf = malloc(size);
> - if (unlikely(!buf))
> + *shader_info = malloc(size);
> + if (unlikely(!*shader_info))
> return -1;
>
> result = vkGetShaderInfo(device, pipeline, stage,
> - VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD, &size, buf);
> - if (unlikely(result != VK_SUCCESS)) {
> - ret = -1;
> - goto fail;
> - }
> -
> - if (unlikely(parse_shader_stats(buf, stats) < 0)) {
> - ret = -1;
> - goto fail;
> - }
> + VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD, &size, *shader_info);
> + if (unlikely(result != VK_SUCCESS))
> + return -1;
>
> -fail:
> - free(buf);
> - return ret;
> + return 0;
> }
>
> static const char *
> @@ -229,8 +225,8 @@ get_shader_stage_name(VkShaderStageFlagBits stage)
> }
>
> static void
> -print_shader_stats(const char *pipeline_name, VkShaderStageFlagBits stage,
> - const struct shader_stats *stats)
> +amd_print_shader_stats(const char *pipeline_name, VkShaderStageFlagBits stage,
> + const struct shader_stats *stats)
> {
> pthread_mutex_lock(&printf_mutex);
> printf("%s (%s) - ", pipeline_name, get_shader_stage_name(stage));
> @@ -364,18 +360,42 @@ create_pipeline(VkDevice device, const char *pipeline_name,
> for (uint32_t i = 0; i < info->stageCount; i++) {
> VkPipelineShaderStageCreateInfo *pCreateInfo = &info->pShaderStagesInfo[i];
> VkShaderStageFlagBits stage = pCreateInfo->stage;
> - struct shader_stats stats = {};
>
> if (!is_shader_stage_valid(device, pipeline, stage))
> continue;
>
> - ret = get_shader_stats(device, pipeline, stage, &stats);
> + char *shader_info = NULL;
> + ret = get_shader_info(device, pipeline, stage, &shader_info);
> if (unlikely(ret < 0)) {
> - fprintf(stderr, "Failed to get shader stats!\n");
> + fprintf(stderr, "Failed to get shader info!\n");
> goto fail;
> }
>
> - print_shader_stats(pipeline_name, stage, &stats);
> + if (vendor == VENDOR_AMD) {
> + struct shader_stats stats = {};
> + if (unlikely(amd_parse_shader_stats(shader_info, &stats) < 0)) {
> + ret = -1;
> + free(shader_info);
> + goto fail;
> + }
> + amd_print_shader_stats(pipeline_name, stage, &stats);
> + } else {
> + char *line = NULL;
> +
> + pthread_mutex_lock(&printf_mutex);
> +
> + line = strtok(shader_info, "\r\n");
> + while (line != NULL) {
> + printf("%s - %s\n",
> + current_pipeline_names[omp_get_thread_num()],
> + line);
> + line = strtok(NULL, "\r\n");
> + }
> +
> + pthread_mutex_unlock(&printf_mutex);
> + }
> +
> + free(shader_info);
> }
>
> fail:
> @@ -508,6 +528,7 @@ int main(int argc, char **argv)
>
> VkPhysicalDeviceProperties device_properties;
> vkGetPhysicalDeviceProperties(physical_devices[0], &device_properties);
> + vendor = device_properties.vendorID;
> fprintf(stderr, "GPU: %s\n", device_properties.deviceName);
>
> /* Get queue properties. */
>
More information about the mesa-dev
mailing list