blob: 0b2fc8c97eda4624fa1429d557ceb2141e820697 [file] [log] [blame]
Marat Dukhandc6c77f2020-10-23 19:09:10 -07001#!/usr/bin/env python
2# Copyright 2020 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 os
10import re
11import sys
12import yaml
13
14sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
15from primes import next_prime
16import xngen
17import xnncommon
18
19
20parser = argparse.ArgumentParser(
Marat Dukhanbf715f92020-10-23 20:17:00 -070021 description='Test generator for DWCONV2D CHW micro-kernels')
Marat Dukhandc6c77f2020-10-23 19:09:10 -070022parser.add_argument("-s", "--spec", metavar="FILE", required=True,
23 help="Spec (YAML) file")
24parser.add_argument("-o", "--output", metavar="FILE", required=True,
25 help='Output (C++ source) file')
26parser.set_defaults(defines=list())
27
28
29TEST_TEMPLATE = """\
30$if SUBSAMPLING == 1:
31 TEST(${TEST_NAME}, output_width_eq_${WIDTH_TILE}) {
32 $if ISA_CHECK:
33 ${ISA_CHECK};
Marat Dukhanbf715f92020-10-23 20:17:00 -070034 DWConv2DMicrokernelTester()
Marat Dukhandc6c77f2020-10-23 19:09:10 -070035 .input_width(${(WIDTH_TILE - 1) * SUBSAMPLING + KERNEL_WIDTH - 2 * PADDING})
36 .input_height(${HEIGHT_TILE * SUBSAMPLING + KERNEL_HEIGHT - 2 * PADDING - 1})
37 .kernel_height(${KERNEL_HEIGHT})
38 .kernel_width(${KERNEL_WIDTH})
39 .subsampling(${SUBSAMPLING})
40 .padding_left(${PADDING})
41 .padding_right(${PADDING})
42 .padding_top(${PADDING})
43 .padding_bottom(${PADDING})
44 .Test(${", ".join(TEST_ARGS)});
45 }
46$else:
47 TEST(${TEST_NAME}, output_width_eq_${WIDTH_TILE}) {
48 $if ISA_CHECK:
49 ${ISA_CHECK};
50 for (size_t input_width = ${(WIDTH_TILE - 1) * SUBSAMPLING + KERNEL_WIDTH - 2 * PADDING}; input_width < ${WIDTH_TILE * SUBSAMPLING + KERNEL_WIDTH - 2 * PADDING}; input_width++) {
Marat Dukhanbf715f92020-10-23 20:17:00 -070051 DWConv2DMicrokernelTester()
Marat Dukhandc6c77f2020-10-23 19:09:10 -070052 .input_width(input_width)
53 .input_height(${HEIGHT_TILE * SUBSAMPLING + KERNEL_HEIGHT - 2 * PADDING - 1})
54 .kernel_height(${KERNEL_HEIGHT})
55 .kernel_width(${KERNEL_WIDTH})
56 .subsampling(${SUBSAMPLING})
57 .padding_left(${PADDING})
58 .padding_right(${PADDING})
59 .padding_top(${PADDING})
60 .padding_bottom(${PADDING})
61 .Test(${", ".join(TEST_ARGS)});
62 }
63 }
64
65$if WIDTH_TILE > 1:
66 TEST(${TEST_NAME}, output_width_div_${WIDTH_TILE}) {
67 $if ISA_CHECK:
68 ${ISA_CHECK};
69 for (size_t input_width = ${2 * WIDTH_TILE * SUBSAMPLING + KERNEL_WIDTH - 2 * PADDING - 1}; input_width < ${8 * WIDTH_TILE * SUBSAMPLING + KERNEL_WIDTH - 2 * PADDING - 1}; input_width += ${WIDTH_TILE * SUBSAMPLING}) {
Marat Dukhanbf715f92020-10-23 20:17:00 -070070 DWConv2DMicrokernelTester()
Marat Dukhandc6c77f2020-10-23 19:09:10 -070071 .input_width(input_width)
72 .input_height(${HEIGHT_TILE * SUBSAMPLING + KERNEL_HEIGHT - 2 * PADDING - 1})
73 .kernel_height(${KERNEL_HEIGHT})
74 .kernel_width(${KERNEL_WIDTH})
75 .subsampling(${SUBSAMPLING})
76 .padding_left(${PADDING})
77 .padding_right(${PADDING})
78 .padding_top(${PADDING})
79 .padding_bottom(${PADDING})
80 .Test(${", ".join(TEST_ARGS)});
81 }
82 }
83
84 TEST(${TEST_NAME}, output_width_lt_${WIDTH_TILE}) {
85 $if ISA_CHECK:
86 ${ISA_CHECK};
87 for (size_t input_width = ${max(1, KERNEL_WIDTH - 2 * PADDING)}; input_width < ${(WIDTH_TILE - 1) * SUBSAMPLING + KERNEL_WIDTH - 2 * PADDING}; input_width++) {
Marat Dukhanbf715f92020-10-23 20:17:00 -070088 DWConv2DMicrokernelTester()
Marat Dukhandc6c77f2020-10-23 19:09:10 -070089 .input_width(${WIDTH_TILE * SUBSAMPLING})
90 .input_height(${HEIGHT_TILE * SUBSAMPLING + KERNEL_HEIGHT - 2 * PADDING - 1})
91 .kernel_height(${KERNEL_HEIGHT})
92 .kernel_width(${KERNEL_WIDTH})
93 .subsampling(${SUBSAMPLING})
94 .padding_left(${PADDING})
95 .padding_right(${PADDING})
96 .padding_top(${PADDING})
97 .padding_bottom(${PADDING})
98 .Test(${", ".join(TEST_ARGS)});
99 }
100 }
101
102TEST(${TEST_NAME}, output_width_gt_${WIDTH_TILE}) {
103 $if ISA_CHECK:
104 ${ISA_CHECK};
105 for (size_t input_width = ${WIDTH_TILE * SUBSAMPLING + KERNEL_WIDTH - 2 * PADDING}; input_width < ${(5 if WIDTH_TILE == 1 else 2) * WIDTH_TILE * SUBSAMPLING + KERNEL_WIDTH - 2 * PADDING}; input_width++) {
Marat Dukhanbf715f92020-10-23 20:17:00 -0700106 DWConv2DMicrokernelTester()
Marat Dukhandc6c77f2020-10-23 19:09:10 -0700107 .input_width(input_width)
108 .input_height(${HEIGHT_TILE * SUBSAMPLING + KERNEL_HEIGHT - 2 * PADDING - 1})
109 .kernel_height(${KERNEL_HEIGHT})
110 .kernel_width(${KERNEL_WIDTH})
111 .subsampling(${SUBSAMPLING})
112 .padding_left(${PADDING})
113 .padding_right(${PADDING})
114 .padding_top(${PADDING})
115 .padding_bottom(${PADDING})
116 .Test(${", ".join(TEST_ARGS)});
117 }
118}
119
120$if SUBSAMPLING > 1:
121 TEST(${TEST_NAME}, output_height_eq_${HEIGHT_TILE}) {
122 $if ISA_CHECK:
123 ${ISA_CHECK};
124 for (size_t input_height = ${(HEIGHT_TILE - 1) * SUBSAMPLING + KERNEL_HEIGHT - 2 * PADDING}; input_height < ${HEIGHT_TILE * SUBSAMPLING + KERNEL_HEIGHT - 2 * PADDING}; input_height++) {
125 for (size_t input_width = 1; input_width < ${5 * WIDTH_TILE * SUBSAMPLING + KERNEL_WIDTH - 2 * PADDING}; input_width += ${max(1, WIDTH_TILE * SUBSAMPLING - 1)}) {
Marat Dukhanbf715f92020-10-23 20:17:00 -0700126 DWConv2DMicrokernelTester()
Marat Dukhandc6c77f2020-10-23 19:09:10 -0700127 .input_width(input_width)
128 .input_height(input_height)
129 .kernel_height(${KERNEL_HEIGHT})
130 .kernel_width(${KERNEL_WIDTH})
131 .subsampling(${SUBSAMPLING})
132 .padding_left(${PADDING})
133 .padding_right(${PADDING})
134 .padding_top(${PADDING})
135 .padding_bottom(${PADDING})
136 .Test(${", ".join(TEST_ARGS)});
137 }
138 }
139 }
140
141$if HEIGHT_TILE > 1:
142 TEST(${TEST_NAME}, output_height_div_${HEIGHT_TILE}) {
143 $if ISA_CHECK:
144 ${ISA_CHECK};
145 for (size_t input_height = ${2 * HEIGHT_TILE * SUBSAMPLING + KERNEL_HEIGHT - 2 * PADDING - 1}; input_height < ${8 * HEIGHT_TILE * SUBSAMPLING + KERNEL_HEIGHT - 2 * PADDING - 1}; input_height += ${HEIGHT_TILE * SUBSAMPLING}) {
146 for (size_t input_width = 1; input_width < ${5 * WIDTH_TILE * SUBSAMPLING + KERNEL_WIDTH - 2 * PADDING}; input_width += ${max(1, WIDTH_TILE * SUBSAMPLING - 1)}) {
Marat Dukhanbf715f92020-10-23 20:17:00 -0700147 DWConv2DMicrokernelTester()
Marat Dukhandc6c77f2020-10-23 19:09:10 -0700148 .input_width(input_width)
149 .input_height(input_height)
150 .kernel_height(${KERNEL_HEIGHT})
151 .kernel_width(${KERNEL_WIDTH})
152 .subsampling(${SUBSAMPLING})
153 .padding_left(${PADDING})
154 .padding_right(${PADDING})
155 .padding_top(${PADDING})
156 .padding_bottom(${PADDING})
157 .Test(${", ".join(TEST_ARGS)});
158 }
159 }
160 }
161
162 TEST(${TEST_NAME}, output_height_lt_${HEIGHT_TILE}) {
163 $if ISA_CHECK:
164 ${ISA_CHECK};
165 for (size_t input_height = ${max(1, KERNEL_HEIGHT - 2 * PADDING)}; input_height < ${(HEIGHT_TILE - 1) * SUBSAMPLING + KERNEL_HEIGHT - 2 * PADDING}; input_height++) {
166 for (size_t input_width = 1; input_width < ${5 * WIDTH_TILE * SUBSAMPLING + KERNEL_WIDTH - 2 * PADDING}; input_width += ${max(1, WIDTH_TILE * SUBSAMPLING - 1)}) {
Marat Dukhanbf715f92020-10-23 20:17:00 -0700167 DWConv2DMicrokernelTester()
Marat Dukhandc6c77f2020-10-23 19:09:10 -0700168 .input_width(input_width)
169 .input_height(input_height)
170 .kernel_height(${KERNEL_HEIGHT})
171 .kernel_width(${KERNEL_WIDTH})
172 .subsampling(${SUBSAMPLING})
173 .padding_left(${PADDING})
174 .padding_right(${PADDING})
175 .padding_top(${PADDING})
176 .padding_bottom(${PADDING})
177 .Test(${", ".join(TEST_ARGS)});
178 }
179 }
180 }
181
182TEST(${TEST_NAME}, output_height_gt_${HEIGHT_TILE}) {
183 $if ISA_CHECK:
184 ${ISA_CHECK};
185 for (size_t input_height = ${HEIGHT_TILE * SUBSAMPLING + KERNEL_HEIGHT - 2 * PADDING}; input_height < ${(5 if WIDTH_TILE == 1 else 2) * HEIGHT_TILE * SUBSAMPLING + KERNEL_HEIGHT - 2 * PADDING}; input_height++) {
186 for (size_t input_width = 1; input_width < ${5 * WIDTH_TILE * SUBSAMPLING + KERNEL_WIDTH - 2 * PADDING}; input_width += ${max(1, WIDTH_TILE * SUBSAMPLING - 1)}) {
Marat Dukhanbf715f92020-10-23 20:17:00 -0700187 DWConv2DMicrokernelTester()
Marat Dukhandc6c77f2020-10-23 19:09:10 -0700188 .input_width(input_width)
189 .input_height(input_height)
190 .kernel_height(${KERNEL_HEIGHT})
191 .kernel_width(${KERNEL_WIDTH})
192 .subsampling(${SUBSAMPLING})
193 .padding_left(${PADDING})
194 .padding_right(${PADDING})
195 .padding_top(${PADDING})
196 .padding_bottom(${PADDING})
197 .Test(${", ".join(TEST_ARGS)});
198 }
199 }
200}
201
202$if SUBSAMPLING > 1:
203 TEST(${TEST_NAME}, padding_top_eq_${SUBSAMPLING - 1}) {
204 $if ISA_CHECK:
205 ${ISA_CHECK};
206 for (size_t input_height = ${max(1, KERNEL_HEIGHT - 2 * PADDING + 1)}; input_height < ${3 * HEIGHT_TILE * SUBSAMPLING + KERNEL_HEIGHT - 2 * PADDING + 1}; input_height++) {
207 for (size_t input_width = 1; input_width < ${5 * WIDTH_TILE * SUBSAMPLING + KERNEL_WIDTH - 2 * PADDING}; input_width += ${max(1, WIDTH_TILE * SUBSAMPLING - 1)}) {
Marat Dukhanbf715f92020-10-23 20:17:00 -0700208 DWConv2DMicrokernelTester()
Marat Dukhandc6c77f2020-10-23 19:09:10 -0700209 .input_width(input_width)
210 .input_height(input_height)
211 .kernel_height(${KERNEL_HEIGHT})
212 .kernel_width(${KERNEL_WIDTH})
213 .subsampling(${SUBSAMPLING})
214 .padding_left(${PADDING})
215 .padding_right(${PADDING})
216 .padding_top(${PADDING - 1})
217 .padding_bottom(${PADDING})
218 .Test(${", ".join(TEST_ARGS)});
219 }
220 }
221 }
222"""
223
224def split_ukernel_name(name):
Marat Dukhanbf715f92020-10-23 20:17:00 -0700225 match = re.match(r"^xnn_(f16|f32)_dwconv2d_chw_ukernel_(\d+)x(\d+)(s2)?p(\d+)__(.+)_(\d+)x(\d+)(_acc\d+)?$", name)
Marat Dukhandc6c77f2020-10-23 19:09:10 -0700226 assert match is not None
227 kernel_height, kernel_width = int(match.group(2)), int(match.group(3))
228 if match.group(4):
229 assert match.group(4).startswith("s")
230 stride = int(match.group(4)[1:])
231 else:
232 stride = 1
233 padding = int(match.group(5))
234
235 height_tile = int(match.group(7))
236 width_tile = int(match.group(8))
237
238 arch, isa = xnncommon.parse_target_name(target_name=match.group(6))
239 return kernel_height, kernel_width, stride, padding, arch, isa, \
240 height_tile, width_tile
241
242
243def generate_test_cases(ukernel, kernel_height, kernel_width, subsampling, \
244 padding, isa, height_tile, width_tile):
Marat Dukhanbf715f92020-10-23 20:17:00 -0700245 """Generates all tests cases for a DWCONV2D CHW micro-kernel.
Marat Dukhandc6c77f2020-10-23 19:09:10 -0700246
247 Args:
248 ukernel: C name of the micro-kernel function.
249 kernel_height: convolution kernel height assumed by the micro-kernel.
250 kernel_width: convolution kernel width assumed by the micro-kernel.
251 subsampling: convolution subsampling (stride) assumed by the micro-kernel.
252 The same subsampling factor is assumed for both horizontal and
253 vertical directions.
254 padding: convolution padding value assumed by the micro-kernel for right,
255 bottom, and left padding. If convolution stride is 1, the same
256 padding value is assumed for the top padding. If convolution stride
257 is different than 1, top padding is specified via micro-kernel
258 parameter, and can be either padding or (padding - 1).
259 isa: instruction set required to run the micro-kernel. Generated unit test
260 will skip execution if the host processor doesn't support this ISA.
261 height_tile: number of output rows processed in one iteration of the main
262 loop of the micro-kernel.
263 width_tile: number of output columns processed in one iteration of the main
264 loop of the micro-kernel.
265
266 Returns:
267 Code for the test case.
268 """
269 _, test_name = ukernel.split("_", 1)
270 _, datatype, ukernel_type, _ = ukernel.split("_", 3)
271 test_args = [ukernel]
Marat Dukhan3de5dfa2020-12-10 11:19:47 -0800272 if not isa:
Marat Dukhanbf715f92020-10-23 20:17:00 -0700273 test_args.append("DWConv2DMicrokernelTester::Variant::Scalar")
Marat Dukhandc6c77f2020-10-23 19:09:10 -0700274 return xngen.preprocess(TEST_TEMPLATE, {
275 "TEST_NAME": test_name.upper().replace("UKERNEL_", ""),
276 "TEST_ARGS": test_args,
277 "UKERNEL_TYPE": ukernel_type.upper(),
278 "DATATYPE": datatype,
279 "KERNEL_HEIGHT": kernel_height,
280 "KERNEL_WIDTH": kernel_width,
281 "SUBSAMPLING": subsampling,
282 "PADDING": padding,
283 "HEIGHT_TILE": height_tile,
284 "WIDTH_TILE": width_tile,
285 "ISA_CHECK": xnncommon.generate_isa_check_macro(isa),
286 "next_prime": next_prime,
287 })
288
289
290def main(args):
291 options = parser.parse_args(args)
292
293 with codecs.open(options.spec, "r", encoding="utf-8") as spec_file:
294 spec_yaml = yaml.safe_load(spec_file)
295 if not isinstance(spec_yaml, list):
296 raise ValueError("expected a list of micro-kernels in the spec")
297
298 tests = """\
299// Copyright 2020 Google LLC
300//
301// This source code is licensed under the BSD-style license found in the
302// LICENSE file in the root directory of this source tree.
303//
304// Auto-generated file. Do not edit!
305// Specification: {specification}
306// Generator: {generator}
307
308
309#include <gtest/gtest.h>
310
311#include <xnnpack/common.h>
312#include <xnnpack/isa-checks.h>
313
314#include <xnnpack/dwconv.h>
Marat Dukhanbf715f92020-10-23 20:17:00 -0700315#include "dwconv2d-microkernel-tester.h"
Marat Dukhandc6c77f2020-10-23 19:09:10 -0700316""".format(specification=options.spec, generator=sys.argv[0])
317
318 for ukernel_spec in spec_yaml:
319 name = ukernel_spec["name"]
320 pipelined = bool(ukernel_spec.get("pipelined", False))
321 assembly = bool(ukernel_spec.get("assembly", False))
322 kernel_height, kernel_width, subsampling, padding, arch, isa, \
323 height_tile, width_tile = split_ukernel_name(name)
324
325 # specification can override architecture
326 arch = ukernel_spec.get("arch", arch)
327
328 test_case = generate_test_cases(name, kernel_height, kernel_width, \
329 subsampling, padding, isa, \
330 height_tile, width_tile)
331 tests += "\n\n" + xnncommon.postprocess_test_case(test_case, arch, isa, assembly)
332
Frank Barchard1f83cf92021-09-07 14:13:03 -0700333 txt_changed = True
334 if os.path.exists(options.output):
335 with codecs.open(options.output, "r", encoding="utf-8") as output_file:
336 txt_changed = output_file.read() != tests
337
338 if txt_changed:
339 with codecs.open(options.output, "w", encoding="utf-8") as output_file:
340 output_file.write(tests)
Marat Dukhandc6c77f2020-10-23 19:09:10 -0700341
342
343if __name__ == "__main__":
344 main(sys.argv[1:])