blob: 77ce782eb0bef5efb209718ed07b01efb11a13ee [file] [log] [blame]
#!/usr/bin/env python3
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Updates op coverage table.
Example usage: ./update_op_coverage.py IREE_BUILD_DIR
"""
import argparse
import collections
import os
import subprocess
import utils
# The symbols to show in the table if the operation is supported or not.
SUCCESS_ELEMENT = '<span class="success-table-element">✓</span>'
FAILURE_ELEMENT = '<span class="failure-table-element">✗</span>'
E2E_XLA_OPS_PATH = 'iree/test/e2e/xla_ops'
# TODO(scotttodd): LLVM AOT (dylib-llvm-aot) HAL target(s)
OP_COVERAGE_DESCRIPTION = """# XLA HLO Op Coverage
There are three backend [targets](https://github.com/google/iree/tree/main/iree/compiler/Dialect/HAL/Target) in IREE:
- vmla
- llvm-ir
- vulkan-spirv
The table shows the supported XLA HLO ops on each backend. It is auto-generated
from IREE's test status.
"""
def parse_arguments():
"""Parses command-line options."""
parser = argparse.ArgumentParser(
description='Generates Markdown files for op coverage table')
parser.add_argument('build_dir',
metavar='BUILD_PATH',
type=str,
help='Base build directory.')
parsed_args = parser.parse_args()
if not os.path.isdir(parsed_args.build_dir):
raise parser.error('expected path to a directory')
return parsed_args
def get_backend_op_pair(test):
"""Returns the target backend and operation pair of the test."""
test_suite_backends = {
'check_vmla_vmla': 'vmla',
'check_llvm-ir_llvm': 'llvm-ir',
'check_vulkan-spirv_vulkan': 'vulkan-spirv'
}
for (test_suite, backend) in test_suite_backends.items():
if test_suite in test:
# Format: ...TEST_SUITE_OP.mlir
start_idx = test.index(test_suite) + len(test_suite) + 1
return backend, test[start_idx:-len('.mlir')]
raise LookupError(f'Can not find a backend to match {test}')
def get_tested_ops_for_backends(build_dir):
"""Parses current op tests for each backend."""
completed_process = subprocess.run(
['ctest', '-N', '-L', E2E_XLA_OPS_PATH],
cwd=build_dir,
# TODO(#4131) python>=3.7: Use capture_output=True.
stderr=subprocess.PIPE,
stdout=subprocess.PIPE,
# TODO(#4131) python>=3.7: Replace 'universal_newlines' with 'text'.
universal_newlines=True)
tests = completed_process.stdout.strip().split('\n')
res = collections.defaultdict(list)
for t in tests:
if not t.endswith('.mlir'):
continue
backend, op = get_backend_op_pair(t)
res[backend].append(op)
return res
def generate_table(build_dir):
"""Generates an op coverage Markdown table for each backend."""
backend_ops = get_tested_ops_for_backends(build_dir)
backends = list(backend_ops.keys())
all_ops = []
for ops in backend_ops.values():
all_ops.extend(ops)
all_ops = list(set(all_ops))
all_ops.sort()
first_row = ['op'] + backends
second_row = [':-:' for _ in first_row]
rows = [first_row, second_row]
for op in all_ops:
row = [op]
for backend in backends:
row.append(SUCCESS_ELEMENT if (
op in backend_ops[backend]) else FAILURE_ELEMENT)
rows.append(row)
return utils.create_markdown_table(rows)
if __name__ == '__main__':
args = parse_arguments()
content = generate_table(args.build_dir)
table_path = os.path.join(args.build_dir, 'doc', 'xla_op_coverage.md')
with open(table_path, 'w', encoding='utf-8') as f:
f.write(OP_COVERAGE_DESCRIPTION)
f.write(content)