[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