[Mlir-commits] [mlir] 4837562 - [MLIR][SPIRV] Extend automation script to generate coverage report.
Lei Zhang
llvmlistbot at llvm.org
Tue Jun 23 08:43:07 PDT 2020
Author: ergawy
Date: 2020-06-23T11:42:59-04:00
New Revision: 4837562de4df60063a6933956185e172571ccebe
URL: https://github.com/llvm/llvm-project/commit/4837562de4df60063a6933956185e172571ccebe
DIFF: https://github.com/llvm/llvm-project/commit/4837562de4df60063a6933956185e172571ccebe.diff
LOG: [MLIR][SPIRV] Extend automation script to generate coverage report.
This patch adds a new cli argument to the automation script to generate
a report of the current SPIRV spec instruction coverage. It dumps to the
standard output a YAML string with the coverage information.
Differential Revision: https://reviews.llvm.org/D82006
Added:
mlir/utils/spirv/report_coverage.sh
Modified:
mlir/utils/spirv/gen_spirv_dialect.py
Removed:
################################################################################
diff --git a/mlir/utils/spirv/gen_spirv_dialect.py b/mlir/utils/spirv/gen_spirv_dialect.py
index 5854a74509cd..19bd7cdfef06 100755
--- a/mlir/utils/spirv/gen_spirv_dialect.py
+++ b/mlir/utils/spirv/gen_spirv_dialect.py
@@ -20,6 +20,7 @@
import re
import requests
import textwrap
+import yaml
SPIRV_HTML_SPEC_URL = 'https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html'
SPIRV_JSON_SPEC_URL = 'https://raw.githubusercontent.com/KhronosGroup/SPIRV-Headers/master/include/spirv/unified1/spirv.core.grammar.json'
@@ -72,7 +73,7 @@ def get_spirv_grammar_from_json_spec():
return spirv['operand_kinds'], spirv['instructions']
-def split_list_into_sublists(items, offset):
+def split_list_into_sublists(items):
"""Split the list of items into multiple sublists.
This is to make sure the string composed from each sublist won't exceed
@@ -80,7 +81,6 @@ def split_list_into_sublists(items, offset):
Arguments:
- items: a list of strings
- - offset: the offset in calculating each sublist's length
"""
chuncks = []
chunk = []
@@ -391,7 +391,7 @@ def get_case_symbol(kind_name, case_name):
for case in kind_cases]
# Split them into sublists and concatenate into multiple lines
- case_names = split_list_into_sublists(case_names, 6)
+ case_names = split_list_into_sublists(case_names)
case_names = ['{:6}'.format('') + ', '.join(sublist)
for sublist in case_names]
case_names = ',\n'.join(case_names)
@@ -428,7 +428,7 @@ def gen_opcode(instructions):
opcode_list = [
decl_fmt_str.format(name=inst['opname']) for inst in instructions
]
- opcode_list = split_list_into_sublists(opcode_list, 6)
+ opcode_list = split_list_into_sublists(opcode_list)
opcode_list = [
'{:6}'.format('') + ', '.join(sublist) for sublist in opcode_list
]
@@ -439,6 +439,75 @@ def gen_opcode(instructions):
' ]>;'.format(name='Opcode', lst=opcode_list)
return opcode_str + '\n\n' + enum_attr
+def map_cap_to_opnames(instructions):
+ """Maps capabilities to instructions enabled by those capabilities
+
+ Arguments:
+ - instructions: a list containing a subset of SPIR-V instructions' grammar
+ Returns:
+ - A map with keys representing capabilities and values of lists of
+ instructions enabled by the corresponding key
+ """
+ cap_to_inst = {}
+
+ for inst in instructions:
+ caps = inst['capabilities'] if 'capabilities' in inst else ['0_core_0']
+ for cap in caps:
+ if cap not in cap_to_inst:
+ cap_to_inst[cap] = []
+ cap_to_inst[cap].append(inst['opname'])
+
+ return cap_to_inst
+
+def gen_instr_coverage_report(path, instructions):
+ """Dumps to standard output a YAML report of current instruction coverage
+
+ Arguments:
+ - path: the path to SPIRBase.td
+ - instructions: a list containing all SPIR-V instructions' grammar
+ """
+ with open(path, 'r') as f:
+ content = f.read()
+
+ content = content.split(AUTOGEN_OPCODE_SECTION_MARKER)
+
+ existing_opcodes = [k[11:] for k in re.findall('def SPV_OC_\w+', content[1])]
+ existing_instructions = list(
+ filter(lambda inst: (inst['opname'] in existing_opcodes),
+ instructions))
+
+ instructions_opnames = [inst['opname'] for inst in instructions]
+
+ remaining_opcodes = list(set(instructions_opnames) - set(existing_opcodes))
+ remaining_instructions = list(
+ filter(lambda inst: (inst['opname'] in remaining_opcodes),
+ instructions))
+
+ rem_cap_to_instr = map_cap_to_opnames(remaining_instructions)
+ ex_cap_to_instr = map_cap_to_opnames(existing_instructions)
+
+ rem_cap_to_cov = {}
+
+ # Calculate coverage for each capability
+ for cap in rem_cap_to_instr:
+ if cap not in ex_cap_to_instr:
+ rem_cap_to_cov[cap] = 0.0
+ else:
+ rem_cap_to_cov[cap] = \
+ (len(ex_cap_to_instr[cap]) / (len(ex_cap_to_instr[cap]) \
+ + len(rem_cap_to_instr[cap])))
+
+ report = {}
+
+ # Merge the 3 maps into one report
+ for cap in rem_cap_to_instr:
+ report[cap] = {}
+ report[cap]['Supported Instructions'] = \
+ ex_cap_to_instr[cap] if cap in ex_cap_to_instr else []
+ report[cap]['Unsupported Instructions'] = rem_cap_to_instr[cap]
+ report[cap]['Coverage'] = '{}%'.format(int(rem_cap_to_cov[cap] * 100))
+
+ print(yaml.dump(report))
def update_td_opcodes(path, instructions, filter_list):
"""Updates SPIRBase.td with new generated opcode cases.
@@ -771,7 +840,6 @@ def extract_td_op_info(op_def):
"""Extracts potentially manually specified sections in op's definition.
Arguments: - A string containing the op's TableGen definition
- - doc: the instruction's SPIR-V HTML doc
Returns:
- A dict containing potential manually specified sections
@@ -930,6 +998,8 @@ def update_td_op_definitions(path, instructions, docs, filter_list,
default='Op',
help='SPIR-V instruction category used for choosing '\
'the TableGen base class to define this op')
+ cli_parser.add_argument('--gen-inst-coverage', dest='gen_inst_coverage', action='store_true')
+ cli_parser.set_defaults(gen_inst_coverage=False)
args = cli_parser.parse_args()
@@ -956,3 +1026,6 @@ def update_td_op_definitions(path, instructions, docs, filter_list,
print('Done. Note that this script just generates a template; ', end='')
print('please read the spec and update traits, arguments, and ', end='')
print('results accordingly.')
+
+ if args.gen_inst_coverage:
+ gen_instr_coverage_report(args.base_td_path, instructions)
diff --git a/mlir/utils/spirv/report_coverage.sh b/mlir/utils/spirv/report_coverage.sh
new file mode 100755
index 000000000000..63f2f3db0cf9
--- /dev/null
+++ b/mlir/utils/spirv/report_coverage.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+# Script for reporting current level of SPIR-V spec instruction coverage in spv
+# Dialect. It dumps to standard output a YAML string of current coverage.
+#
+# Run as:
+# ./report_coverage.sh
+
+set -e
+
+current_file="$(readlink -f "$0")"
+current_dir="$(dirname "$current_file")"
+
+python3 ${current_dir}/gen_spirv_dialect.py \
+ --base-td-path ${current_dir}/../../include/mlir/Dialect/SPIRV/SPIRVBase.td \
+ --gen-inst-coverage
More information about the Mlir-commits
mailing list