From: Timothy Arceri <tarceri@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. */ -- 2.17.1 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev