blob: 4a0cc048d1d689fd7b9e4379cb61c4c66003011e [file] [log] [blame]
Marat Dukhanc07cb7f2019-11-14 15:32:05 -08001#!/usr/bin/env python
2# Copyright 2019 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__)))
16import xngen
17import xnncommon
18
19
20parser = argparse.ArgumentParser(
21 description='Vector binary operation 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):
Marat Dukhan13bafb02020-06-05 00:43:11 -070030 match = re.match(r"^xnn_(f16|f32)_v(add|div|max|min|mul|sqrdiff|sub|addc|divc|rdivc|maxc|minc|mulc|sqrdiffc|rsqrdiffc|subc|rsubc)(_(minmax))?_ukernel__(.+)_x(\d+)$", name)
Marat Dukhanc07cb7f2019-11-14 15:32:05 -080031 if match is None:
32 raise ValueError("Unexpected microkernel name: " + name)
33 op_type = {
34 "add": "Add",
Marat Dukhan77ca6302019-12-06 12:48:15 -080035 "div": "Div",
Marat Dukhan403b7d42019-12-05 12:49:11 -080036 "max": "Max",
37 "min": "Min",
Marat Dukhanc07cb7f2019-11-14 15:32:05 -080038 "mul": "Mul",
Marat Dukhan13bafb02020-06-05 00:43:11 -070039 "sqrdiff": "SqrDiff",
Marat Dukhanc07cb7f2019-11-14 15:32:05 -080040 "sub": "Sub",
41 "addc": "AddC",
Marat Dukhan77ca6302019-12-06 12:48:15 -080042 "divc": "DivC",
43 "rdivc": "RDivC",
Marat Dukhan403b7d42019-12-05 12:49:11 -080044 "maxc": "MaxC",
45 "minc": "MinC",
Marat Dukhanc07cb7f2019-11-14 15:32:05 -080046 "mulc": "MulC",
Marat Dukhan13bafb02020-06-05 00:43:11 -070047 "sqrdiffc": "SqrDiffC",
48 "rsqrdiffc": "RSqrDiffC",
Marat Dukhanc07cb7f2019-11-14 15:32:05 -080049 "subc": "SubC",
50 "rsubc": "RSubC",
51 }[match.group(2)]
Marat Dukhan91cd2b72020-04-09 23:57:31 -070052 batch_tile = int(match.group(6))
Marat Dukhanc07cb7f2019-11-14 15:32:05 -080053
Marat Dukhan13bafb02020-06-05 00:43:11 -070054 activation_type = match.group(4)
55 if activation_type is None:
56 activation_type = "LINEAR"
57 else:
58 activation_type = activation_type.upper()
59
Marat Dukhan91cd2b72020-04-09 23:57:31 -070060 arch, isa = xnncommon.parse_target_name(target_name=match.group(5))
Marat Dukhan13bafb02020-06-05 00:43:11 -070061 return op_type, activation_type, batch_tile, arch, isa
Marat Dukhanc07cb7f2019-11-14 15:32:05 -080062
63
64BINOP_TEST_TEMPLATE = """\
65TEST(${TEST_NAME}, batch_eq_${BATCH_TILE}) {
66 $if ISA_CHECK:
67 ${ISA_CHECK};
68 ${TESTER}()
69 .batch_size(${BATCH_TILE})
70 .Test(${", ".join(TEST_ARGS)});
71}
72
73$if BATCH_TILE > 1:
74 TEST(${TEST_NAME}, batch_div_${BATCH_TILE}) {
75 $if ISA_CHECK:
76 ${ISA_CHECK};
77 for (size_t batch_size = ${BATCH_TILE*2}; batch_size < ${BATCH_TILE*10}; batch_size += ${BATCH_TILE}) {
78 ${TESTER}()
79 .batch_size(batch_size)
80 .Test(${", ".join(TEST_ARGS)});
81 }
82 }
83
84 TEST(${TEST_NAME}, batch_lt_${BATCH_TILE}) {
85 $if ISA_CHECK:
86 ${ISA_CHECK};
87 for (size_t batch_size = 1; batch_size < ${BATCH_TILE}; batch_size++) {
88 ${TESTER}()
89 .batch_size(batch_size)
90 .Test(${", ".join(TEST_ARGS)});
91 }
92 }
93
94TEST(${TEST_NAME}, batch_gt_${BATCH_TILE}) {
95 $if ISA_CHECK:
96 ${ISA_CHECK};
97 for (size_t batch_size = ${BATCH_TILE+1}; batch_size < ${10 if BATCH_TILE == 1 else BATCH_TILE*2}; batch_size++) {
98 ${TESTER}()
99 .batch_size(batch_size)
100 .Test(${", ".join(TEST_ARGS)});
101 }
102}
103
104$if TESTER == "VBinOpCMicrokernelTester":
105 TEST(${TEST_NAME}, inplace) {
106 $if ISA_CHECK:
107 ${ISA_CHECK};
108 for (size_t batch_size = 1; batch_size <= ${BATCH_TILE*5}; batch_size += ${max(1, BATCH_TILE-1)}) {
109 ${TESTER}()
110 .batch_size(batch_size)
111 .inplace(true)
112 .Test(${", ".join(TEST_ARGS)});
113 }
114 }
115$else:
116 TEST(${TEST_NAME}, inplace_a) {
117 $if ISA_CHECK:
118 ${ISA_CHECK};
119 for (size_t batch_size = 1; batch_size <= ${BATCH_TILE*5}; batch_size += ${max(1, BATCH_TILE-1)}) {
120 ${TESTER}()
121 .batch_size(batch_size)
122 .inplace_a(true)
123 .Test(${", ".join(TEST_ARGS)});
124 }
125 }
126
127 TEST(${TEST_NAME}, inplace_b) {
128 $if ISA_CHECK:
129 ${ISA_CHECK};
130 for (size_t batch_size = 1; batch_size <= ${BATCH_TILE*5}; batch_size += ${max(1, BATCH_TILE-1)}) {
131 ${TESTER}()
132 .batch_size(batch_size)
133 .inplace_b(true)
134 .Test(${", ".join(TEST_ARGS)});
135 }
136 }
137
138 TEST(${TEST_NAME}, inplace_a_and_b) {
139 $if ISA_CHECK:
140 ${ISA_CHECK};
141 for (size_t batch_size = 1; batch_size <= ${BATCH_TILE*5}; batch_size += ${max(1, BATCH_TILE-1)}) {
142 ${TESTER}()
143 .batch_size(batch_size)
144 .inplace_a(true)
145 .inplace_b(true)
146 .Test(${", ".join(TEST_ARGS)});
147 }
148 }
149
Marat Dukhan13bafb02020-06-05 00:43:11 -0700150$if ACTIVATION_TYPE == "MINMAX":
151 TEST(${TEST_NAME}, qmin) {
152 $if ISA_CHECK:
153 ${ISA_CHECK};
154 for (size_t batch_size = 1; batch_size <= ${BATCH_TILE*5}; batch_size += ${max(1, BATCH_TILE-1)}) {
155 ${TESTER}()
156 .batch_size(batch_size)
157 .qmin(128)
158 .Test(${", ".join(TEST_ARGS)});
159 }
Marat Dukhanc07cb7f2019-11-14 15:32:05 -0800160 }
Marat Dukhanc07cb7f2019-11-14 15:32:05 -0800161
Marat Dukhan13bafb02020-06-05 00:43:11 -0700162 TEST(${TEST_NAME}, qmax) {
163 $if ISA_CHECK:
164 ${ISA_CHECK};
165 for (size_t batch_size = 1; batch_size <= ${BATCH_TILE*5}; batch_size += ${max(1, BATCH_TILE-1)}) {
166 ${TESTER}()
167 .batch_size(batch_size)
168 .qmax(128)
169 .Test(${", ".join(TEST_ARGS)});
170 }
Marat Dukhanc07cb7f2019-11-14 15:32:05 -0800171 }
Marat Dukhanc07cb7f2019-11-14 15:32:05 -0800172"""
173
174
Marat Dukhan13bafb02020-06-05 00:43:11 -0700175def generate_test_cases(ukernel, op_type, activation_type, batch_tile, isa):
Marat Dukhanc07cb7f2019-11-14 15:32:05 -0800176 """Generates all tests cases for a Vector Binary Operation micro-kernel.
177
178 Args:
179 ukernel: C name of the micro-kernel function.
180 op_type: Operation type (ADD/MUL/SUB/etc).
Marat Dukhan13bafb02020-06-05 00:43:11 -0700181 activation_type: Activation type (LINEAR/MINMAX/RELU).
Marat Dukhanc07cb7f2019-11-14 15:32:05 -0800182 batch_tile: Number of batch elements processed per one iteration of the
183 inner loop of the micro-kernel.
184 isa: instruction set required to run the micro-kernel. Generated unit test
185 will skip execution if the host processor doesn't support this ISA.
186
187 Returns:
188 Code for the test case.
189 """
190 _, test_name = ukernel.split("_", 1)
191 _, datatype, _ = ukernel.split("_", 2)
192 tester = "VBinOp%sMicrokernelTester" % ("C" if op_type.endswith("C") else "")
193 test_args = [
194 ukernel,
195 "%s::OpType::%s" % (tester, op_type),
196 ]
197 if not isa or isa == "psimd":
198 test_args.append("%s::Variant::Scalar" % tester)
199 return xngen.preprocess(BINOP_TEST_TEMPLATE, {
200 "TEST_NAME": test_name.upper().replace("UKERNEL_", ""),
201 "TEST_ARGS": test_args,
202 "TESTER": tester,
203 "DATATYPE": datatype,
204 "BATCH_TILE": batch_tile,
205 "OP_TYPE": op_type,
Marat Dukhan13bafb02020-06-05 00:43:11 -0700206 "ACTIVATION_TYPE": activation_type,
Marat Dukhanc07cb7f2019-11-14 15:32:05 -0800207 "ISA_CHECK": xnncommon.generate_isa_check_macro(isa),
208 })
209
210
211def main(args):
212 options = parser.parse_args(args)
213
214 with codecs.open(options.spec, "r", encoding="utf-8") as spec_file:
215 spec_yaml = yaml.safe_load(spec_file)
216 if not isinstance(spec_yaml, list):
217 raise ValueError("expected a list of micro-kernels in the spec")
218
Marat Dukhan91cd2b72020-04-09 23:57:31 -0700219 spec_name = os.path.splitext(os.path.split(options.spec)[1])[0]
220 opname = spec_name.split("-")[1]
221 if opname.endswith("c"):
Marat Dukhan1e782c42019-11-21 17:02:40 -0800222 header = "vbinaryc-microkernel-tester.h"
Marat Dukhanc07cb7f2019-11-14 15:32:05 -0800223 else:
Marat Dukhan1e782c42019-11-21 17:02:40 -0800224 header = "vbinary-microkernel-tester.h"
Marat Dukhanc07cb7f2019-11-14 15:32:05 -0800225 tests = """\
226// Copyright 2019 Google LLC
227//
228// This source code is licensed under the BSD-style license found in the
229// LICENSE file in the root directory of this source tree.
230//
231// Auto-generated file. Do not edit!
232// Specification: {specification}
233// Generator: {generator}
234
235
236#include <gtest/gtest.h>
237
238#include <xnnpack/common.h>
239#include <xnnpack/isa-checks.h>
240
Marat Dukhan1e782c42019-11-21 17:02:40 -0800241#include <xnnpack/vbinary.h>
Marat Dukhanc07cb7f2019-11-14 15:32:05 -0800242#include "{header}"
243""".format(specification=options.spec, generator=sys.argv[0], header=header)
244
245 for ukernel_spec in spec_yaml:
246 name = ukernel_spec["name"]
Marat Dukhan13bafb02020-06-05 00:43:11 -0700247 op_type, activation_type, batch_tile, arch, isa = split_ukernel_name(name)
Marat Dukhanc07cb7f2019-11-14 15:32:05 -0800248
249 # specification can override architecture
250 arch = ukernel_spec.get("arch", arch)
251
Marat Dukhan13bafb02020-06-05 00:43:11 -0700252 test_case = generate_test_cases(name, op_type, activation_type,
253 batch_tile, isa)
Marat Dukhanc07cb7f2019-11-14 15:32:05 -0800254 tests += "\n\n" + xnncommon.postprocess_test_case(test_case, arch, isa)
255
256 with codecs.open(options.output, "w", encoding="utf-8") as output_file:
257 output_file.write(tests)
258
259
260if __name__ == "__main__":
261 main(sys.argv[1:])