1#!/usr/bin/env python 2# Copyright 2022 Google LLC 3# 4# This source code is licensed under the BSD-style license found in the 5# LICENSE file in the root directory of this source tree. 6 7import argparse 8import codecs 9import math 10import os 11import re 12import sys 13import yaml 14 15sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) 16from primes import next_prime 17import xngen 18import xnncommon 19 20 21parser = argparse.ArgumentParser(description='Fftr microkernel test generator') 22parser.add_argument("-s", "--spec", metavar="FILE", required=True, 23 help="Specification (YAML) file") 24parser.add_argument("-o", "--output", metavar="FILE", required=True, 25 help='Output (C++ source) file') 26parser.set_defaults(defines=list()) 27 28 29def split_ukernel_name(name): 30 match = re.fullmatch(r"xnn_cs16_fftr_ukernel__(.+)_x(\d+)", name) 31 assert match is not None 32 sample_tile = int(match.group(2)) 33 34 arch, isa = xnncommon.parse_target_name(target_name=match.group(1)) 35 return sample_tile, arch, isa 36 37 38FFTR_TEST_TEMPLATE = """\ 39TEST(${TEST_NAME}, samples_eq_256) { 40 $if ISA_CHECK: 41 ${ISA_CHECK}; 42 FftrMicrokernelTester() 43 .samples(256) 44 .Test(${", ".join(TEST_ARGS)}); 45} 46 47""" 48 49 50def generate_test_cases(ukernel, sample_tile, isa): 51 """Generates all tests cases for a Fftr micro-kernel. 52 53 Args: 54 ukernel: C name of the micro-kernel function. 55 sample_tile: Number of samples processed per one iteration of the inner 56 loop of the micro-kernel. 57 isa: instruction set required to run the micro-kernel. Generated unit test 58 will skip execution if the host processor doesn't support this ISA. 59 60 Returns: 61 Code for the test case. 62 """ 63 _, test_name = ukernel.split("_", 1) 64 _, datatype, ukernel_type, _ = ukernel.split("_", 3) 65 return xngen.preprocess(FFTR_TEST_TEMPLATE, { 66 "TEST_NAME": test_name.upper().replace("UKERNEL_", ""), 67 "TEST_ARGS": [ukernel], 68 "DATATYPE": datatype, 69 "SAMPLE_TILE": sample_tile, 70 "ISA_CHECK": xnncommon.generate_isa_check_macro(isa), 71 "next_prime": next_prime, 72 }) 73 74 75def main(args): 76 options = parser.parse_args(args) 77 78 with codecs.open(options.spec, "r", encoding="utf-8") as spec_file: 79 spec_yaml = yaml.safe_load(spec_file) 80 if not isinstance(spec_yaml, list): 81 raise ValueError("expected a list of micro-kernels in the spec") 82 83 tests = """\ 84// Copyright 2022 Google LLC 85// 86// This source code is licensed under the BSD-style license found in the 87// LICENSE file in the root directory of this source tree. 88// 89// Auto-generated file. Do not edit! 90// Specification: {specification} 91// Generator: {generator} 92 93 94#include <gtest/gtest.h> 95 96#include <xnnpack/common.h> 97#include <xnnpack/isa-checks.h> 98 99#include <xnnpack/fft.h> 100#include "fftr-microkernel-tester.h" 101""".format(specification=options.spec, generator=sys.argv[0]) 102 103 for ukernel_spec in spec_yaml: 104 name = ukernel_spec["name"] 105 sample_tile, arch, isa = split_ukernel_name(name) 106 107 # specification can override architecture 108 arch = ukernel_spec.get("arch", arch) 109 110 test_case = generate_test_cases(name, sample_tile, isa) 111 tests += "\n\n" + xnncommon.postprocess_test_case(test_case, arch, isa) 112 113 txt_changed = True 114 if os.path.exists(options.output): 115 with codecs.open(options.output, "r", encoding="utf-8") as output_file: 116 txt_changed = output_file.read() != tests 117 118 if txt_changed: 119 with codecs.open(options.output, "w", encoding="utf-8") as output_file: 120 output_file.write(tests) 121 122 123if __name__ == "__main__": 124 main(sys.argv[1:]) 125