blob: b3c94a71ef81e49a66b005ee108a73d15db62de9 [file] [log] [blame]
XNNPACK Teamb455b122019-09-27 18:10:33 -07001#!/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 bisect
9import codecs
10import math
11import os
12import sys
13import yaml
14
15sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
16from primes import next_prime
17import xngen
Marat Dukhan918a4a62019-10-27 19:49:49 -070018import xnncommon
XNNPACK Teamb455b122019-09-27 18:10:33 -070019
20
21parser = argparse.ArgumentParser(description='XNNPACK generator')
22parser.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
XNNPACK Teamb455b122019-09-27 18:10:33 -070029def split_ukernel_name(name):
30 common_name, target_name = name.split("__", 1)
31 common_parts = common_name.split("_")
32 param_spec = common_parts[-1]
33 assert param_spec.startswith("up")
34 cr, kr = map(int, param_spec[2:].split("x"))
Marat Dukhan918a4a62019-10-27 19:49:49 -070035 arch, isa = xnncommon.parse_target_name(target_name)
Marat Dukhana5d12612021-05-25 01:12:26 -070036
37 requantization = common_parts[-3]
38 if requantization not in ["gemmlowp", "fp32"]:
39 requantization = None
40
41 return cr, kr, requantization, arch, isa
XNNPACK Teamb455b122019-09-27 18:10:33 -070042
43
44DWCONV_TEST_CODE = """\
45TEST(${TEST_NAME}, c_eq_${CBLOCK}) {
46 $if ISA_CHECK:
47 ${ISA_CHECK};
48 DWConvMicrokernelTester()
49 .cr(${CR})
50 .kr(${KR})
51 .channels(${CBLOCK})
52 .Test(${", ".join(TEST_ARGS)});
53}
54
55$if IS_PIPELINED:
56 TEST(${TEST_NAME}, c_eq_${CBLOCK * 2}) {
57 $if ISA_CHECK:
58 ${ISA_CHECK};
59 DWConvMicrokernelTester()
60 .cr(${CR})
61 .kr(${KR})
62 .channels(${CBLOCK * 2})
63 .Test(${", ".join(TEST_ARGS)});
64 }
65
66$if CBLOCK > 1:
67 TEST(${TEST_NAME}, c_div_${CBLOCK}) {
68 $if ISA_CHECK:
69 ${ISA_CHECK};
70 for (uint32_t channels = ${ADJCBLOCK + CBLOCK}; channels < ${CR * 16}; channels += ${CR * 3}) {
71 DWConvMicrokernelTester()
72 .cr(${CR})
73 .kr(${KR})
74 .channels(channels)
75 .Test(${", ".join(TEST_ARGS)});
76 }
77 }
78
Marat Dukhan163a7e62020-04-09 04:19:26 -070079 $if ACTIVATION == "MINMAX":
80 TEST(${TEST_NAME}, c_div_${CBLOCK}_with_qmin) {
81 $if ISA_CHECK:
82 ${ISA_CHECK};
83 for (uint32_t channels = ${ADJCBLOCK + CBLOCK}; channels < ${CR * 16}; channels += ${CR * 3}) {
84 DWConvMicrokernelTester()
85 .cr(${CR})
86 .kr(${KR})
87 .channels(channels)
88 .qmin(128)
89 .Test(${", ".join(TEST_ARGS)});
90 }
XNNPACK Teamb455b122019-09-27 18:10:33 -070091 }
XNNPACK Teamb455b122019-09-27 18:10:33 -070092
Marat Dukhan163a7e62020-04-09 04:19:26 -070093 TEST(${TEST_NAME}, c_div_${CBLOCK}_with_qmax) {
94 $if ISA_CHECK:
95 ${ISA_CHECK};
96 for (uint32_t channels = ${ADJCBLOCK + CBLOCK}; channels < ${CR * 16}; channels += ${CR * 3}) {
97 DWConvMicrokernelTester()
98 .cr(${CR})
99 .kr(${KR})
100 .channels(channels)
101 .qmax(128)
102 .Test(${", ".join(TEST_ARGS)});
103 }
XNNPACK Teamb455b122019-09-27 18:10:33 -0700104 }
XNNPACK Teamb455b122019-09-27 18:10:33 -0700105
106 TEST(${TEST_NAME}, c_lt_${ADJCBLOCK}) {
107 $if ISA_CHECK:
108 ${ISA_CHECK};
109 for (uint32_t channels = 1; channels < ${ADJCBLOCK}; channels++) {
110 DWConvMicrokernelTester()
111 .cr(${CR})
112 .kr(${KR})
113 .channels(channels)
114 .Test(${", ".join(TEST_ARGS)});
115 }
116 }
117
118TEST(${TEST_NAME}, c_gt_${ADJCBLOCK}) {
119 $if ISA_CHECK:
120 ${ISA_CHECK};
121 for (uint32_t channels = ${ADJCBLOCK + 1}; channels < ${10 if CBLOCK == 1 else ADJCBLOCK + CBLOCK}; channels++) {
122 DWConvMicrokernelTester()
123 .cr(${CR})
124 .kr(${KR})
125 .channels(channels)
126 .Test(${", ".join(TEST_ARGS)});
127 }
128}
129
Marat Dukhan163a7e62020-04-09 04:19:26 -0700130$if ACTIVATION == "MINMAX":
131 TEST(${TEST_NAME}, c_gt_${ADJCBLOCK}_with_qmin) {
132 $if ISA_CHECK:
133 ${ISA_CHECK};
134 for (uint32_t channels = ${ADJCBLOCK + 1}; channels < ${10 if CBLOCK == 1 else ADJCBLOCK + CBLOCK}; channels++) {
135 DWConvMicrokernelTester()
136 .cr(${CR})
137 .kr(${KR})
138 .channels(channels)
139 .qmin(128)
140 .Test(${", ".join(TEST_ARGS)});
141 }
XNNPACK Teamb455b122019-09-27 18:10:33 -0700142 }
XNNPACK Teamb455b122019-09-27 18:10:33 -0700143
Marat Dukhan163a7e62020-04-09 04:19:26 -0700144 TEST(${TEST_NAME}, c_gt_${ADJCBLOCK}_with_qmax) {
145 $if ISA_CHECK:
146 ${ISA_CHECK};
147 for (uint32_t channels = ${ADJCBLOCK + 1}; channels < ${10 if CBLOCK == 1 else ADJCBLOCK + CBLOCK}; channels++) {
148 DWConvMicrokernelTester()
149 .cr(${CR})
150 .kr(${KR})
151 .channels(channels)
152 .qmax(128)
153 .Test(${", ".join(TEST_ARGS)});
154 }
XNNPACK Teamb455b122019-09-27 18:10:33 -0700155 }
XNNPACK Teamb455b122019-09-27 18:10:33 -0700156
157TEST(${TEST_NAME}, multipixel) {
158 $if ISA_CHECK:
159 ${ISA_CHECK};
160 for (size_t channels = 1; channels <= ${CBLOCK * 5}; channels += ${max(1, CBLOCK - 1)}) {
161 DWConvMicrokernelTester()
162 .cr(${CR})
163 .kr(${KR})
164 .channels(channels)
165 .width(3)
166 .Test(${", ".join(TEST_ARGS)});
167 }
168}
169
170TEST(${TEST_NAME}, multipixel_with_step) {
171 $if ISA_CHECK:
172 ${ISA_CHECK};
173 for (size_t channels = 1; channels <= ${CBLOCK * 5}; channels += ${max(1, CBLOCK - 1)}) {
174 for (size_t step = 2; step <= ${KR}; step++) {
175 DWConvMicrokernelTester()
176 .cr(${CR})
177 .kr(${KR})
178 .channels(channels)
179 .width(3)
180 .step(step)
181 .Test(${", ".join(TEST_ARGS)});
182 }
183 }
184}
185
186TEST(${TEST_NAME}, multipixel_with_output_stride) {
187 $if ISA_CHECK:
188 ${ISA_CHECK};
189 for (size_t channels = 1; channels <= ${CBLOCK * 5}; channels += ${max(1, CBLOCK - 1)}) {
190 DWConvMicrokernelTester()
191 .cr(${CR})
192 .kr(${KR})
193 .channels(${CR})
194 .width(5)
195 .output_stride(${next_prime(CR * 5 + 1)})
196 .Test(${", ".join(TEST_ARGS)});
197 }
198}
199
Marat Dukhan163a7e62020-04-09 04:19:26 -0700200$if ACTIVATION == "MINMAX":
201 TEST(${TEST_NAME}, multipixel_with_qmin) {
202 $if ISA_CHECK:
203 ${ISA_CHECK};
204 for (size_t channels = 1; channels <= ${CBLOCK * 5}; channels += ${max(1, CBLOCK - 1)}) {
205 DWConvMicrokernelTester()
206 .cr(${CR})
207 .kr(${KR})
208 .channels(channels)
209 .width(3)
210 .qmin(128)
211 .Test(${", ".join(TEST_ARGS)});
212 }
XNNPACK Teamb455b122019-09-27 18:10:33 -0700213 }
XNNPACK Teamb455b122019-09-27 18:10:33 -0700214
Marat Dukhan163a7e62020-04-09 04:19:26 -0700215 TEST(${TEST_NAME}, multipixel_with_qmax) {
216 $if ISA_CHECK:
217 ${ISA_CHECK};
218 for (size_t channels = 1; channels <= ${CBLOCK * 5}; channels += ${max(1, CBLOCK - 1)}) {
219 DWConvMicrokernelTester()
220 .cr(${CR})
221 .kr(${KR})
222 .channels(channels)
223 .width(3)
224 .qmax(128)
225 .Test(${", ".join(TEST_ARGS)});
226 }
XNNPACK Teamb455b122019-09-27 18:10:33 -0700227 }
XNNPACK Teamb455b122019-09-27 18:10:33 -0700228
Marat Dukhan08b7a972020-07-14 18:17:29 -0700229$if DATATYPE == "qu8":
XNNPACK Teamb455b122019-09-27 18:10:33 -0700230 TEST(${TEST_NAME}, input_zero_point_only) {
231 $if ISA_CHECK:
232 ${ISA_CHECK};
233 for (size_t channels = 1; channels <= ${CBLOCK * 5}; channels += ${max(1, CBLOCK - 1)}) {
234 DWConvMicrokernelTester()
235 .cr(${CR})
236 .kr(${KR})
237 .channels(channels)
238 .width(3)
239 .input_zero_point(255)
240 .kernel_zero_point(0)
241 .Test(${", ".join(TEST_ARGS)});
242 }
243 }
244
245 TEST(${TEST_NAME}, kernel_zero_point_only) {
246 $if ISA_CHECK:
247 ${ISA_CHECK};
248 for (size_t channels = 1; channels <= ${CBLOCK * 5}; channels += ${max(1, CBLOCK - 1)}) {
249 DWConvMicrokernelTester()
250 .cr(${CR})
251 .kr(${KR})
252 .channels(channels)
253 .width(3)
254 .input_zero_point(0)
255 .kernel_zero_point(255)
256 .Test(${", ".join(TEST_ARGS)});
257 }
258 }
XNNPACK Teamb455b122019-09-27 18:10:33 -0700259
Frank Barchardd5360722020-05-17 16:10:36 -0700260TEST(${TEST_NAME}, input_offset) {
261 $if ISA_CHECK:
262 ${ISA_CHECK};
263 for (uint32_t channels = ${ADJCBLOCK + CBLOCK}; channels < ${CR * 16}; channels += ${CR * 3}) {
264 DWConvMicrokernelTester()
265 .cr(${CR})
266 .kr(${KR})
267 .channels(channels)
268 .input_offset(${next_prime(CR + 1) * 16})
269 .Test(${", ".join(TEST_ARGS)});
270 }
271}
272
273TEST(${TEST_NAME}, zero) {
274 $if ISA_CHECK:
275 ${ISA_CHECK};
276 for (uint32_t mz = 0; mz < ${KR}; mz++) {
277 for (uint32_t channels = ${ADJCBLOCK + CBLOCK}; channels < ${CR * 16}; channels += ${CR * 3}) {
278 DWConvMicrokernelTester()
279 .cr(${CR})
280 .kr(${KR})
281 .channels(channels)
282 .input_offset(${next_prime(CR + 1) * 16})
283 .zero_index(mz)
284 .Test(${", ".join(TEST_ARGS)});
285 }
286 }
287}
288"""
XNNPACK Teamb455b122019-09-27 18:10:33 -0700289
Marat Dukhana5d12612021-05-25 01:12:26 -0700290def generate_test_cases(ukernel, cr, kr, c_block,
291 init_fn, requantization, is_pipelined, isa):
XNNPACK Teamb455b122019-09-27 18:10:33 -0700292 """Generates all tests cases for a DWCONV micro-kernel.
293
294 Args:
295 ukernel: C name of the micro-kernel function.
296 cr: CR parameter of the DWCONV micro-kernel.
297 kr: KR parameter of the DWCONV micro-kernel.
298 k_block: Number of C values processed per one iteration of the main loop of
299 the micro-kernel.
Marat Dukhand5694df2021-05-20 17:10:40 -0700300 init_fn: C name of the function to initialize microkernel parameters.
Marat Dukhana5d12612021-05-25 01:12:26 -0700301 requantization: name of the requantization scheme used by the microkernel.
XNNPACK Teamb455b122019-09-27 18:10:33 -0700302 is_pipelined: Indicates if the micro-kernel is implemented with software
303 pipelining. Additional test cases are generated for software
304 pipelined micro-kernels to separately test prologue + epiloque
305 of the pipelined loop and iteration of the pipelined loop.
306 isa: instruction set required to run the micro-kernel. Generated unit test
307 will skip execution if the host processor doesn't support this ISA.
308
309 Returns:
310 Code for the test case.
311 """
312 _, test_name = ukernel.split("_", 1)
Marat Dukhan163a7e62020-04-09 04:19:26 -0700313 _, datatype, ukernel_type, activation, _ = ukernel.split("_", 4)
314 if activation == "ukernel":
315 activation = "linear"
XNNPACK Teamb455b122019-09-27 18:10:33 -0700316 test_args = [ukernel]
Marat Dukhand5694df2021-05-20 17:10:40 -0700317 if init_fn:
318 test_args.append(init_fn)
Marat Dukhana5d12612021-05-25 01:12:26 -0700319 if requantization:
320 test_args += [
321 "xnn_init_qs8_requantization_%s_params" % requantization,
322 "xnn_qs8_requantize_%s" % requantization
323 ]
XNNPACK Teamb455b122019-09-27 18:10:33 -0700324 return xngen.preprocess(DWCONV_TEST_CODE, {
325 "TEST_NAME": test_name.upper().replace("UKERNEL_", ""),
326 "TEST_ARGS": test_args,
327 "UKERNEL_TYPE": ukernel_type.upper(),
328 "DATATYPE": datatype,
Marat Dukhan163a7e62020-04-09 04:19:26 -0700329 "ACTIVATION": activation.upper(),
XNNPACK Teamb455b122019-09-27 18:10:33 -0700330 "CR": cr,
331 "KR": kr,
332 "CBLOCK": c_block,
333 "ADJCBLOCK": 2 * c_block if is_pipelined else c_block,
334 "IS_PIPELINED": is_pipelined,
Marat Dukhan918a4a62019-10-27 19:49:49 -0700335 "ISA_CHECK": xnncommon.generate_isa_check_macro(isa),
XNNPACK Teamb455b122019-09-27 18:10:33 -0700336 "next_prime": next_prime,
337 "sqrt": math.sqrt,
338 })
339
340
341def main(args):
342 options = parser.parse_args(args)
343
344 with codecs.open(options.spec, "r", encoding="utf-8") as spec_file:
345 spec_yaml = yaml.safe_load(spec_file)
346 if not isinstance(spec_yaml, list):
347 raise ValueError("expected a list of micro-kernels in the spec")
348
349 tests = """\
350// Copyright (c) Facebook, Inc. and its affiliates.
351// All rights reserved.
352//
353// Copyright 2019 Google LLC
354//
355// This source code is licensed under the BSD-style license found in the
356// LICENSE file in the root directory of this source tree.
357//
358// Auto-generated file. Do not edit!
359// Specification: {specification}
360// Generator: {generator}
361
362
Marat Dukhan629a33e2019-10-01 10:39:14 -0700363#include <gtest/gtest.h>
XNNPACK Teamb455b122019-09-27 18:10:33 -0700364
Marat Dukhan1dadbf72019-10-01 10:46:20 -0700365#include <xnnpack/common.h>
XNNPACK Teamb455b122019-09-27 18:10:33 -0700366#include <xnnpack/isa-checks.h>
367
Marat Dukhan1dadbf72019-10-01 10:46:20 -0700368#include <xnnpack/dwconv.h>
XNNPACK Teamb455b122019-09-27 18:10:33 -0700369#include "dwconv-microkernel-tester.h"
370""".format(specification=options.spec, generator=sys.argv[0])
371
372 for ukernel_spec in spec_yaml:
373 name = ukernel_spec["name"]
Marat Dukhand5694df2021-05-20 17:10:40 -0700374 init_fn = ukernel_spec.get("init")
XNNPACK Teamb455b122019-09-27 18:10:33 -0700375 pipelined = bool(ukernel_spec.get("pipelined", False))
Frank Barchard7e955972019-10-11 10:34:25 -0700376 assembly = bool(ukernel_spec.get("assembly", False))
Marat Dukhana5d12612021-05-25 01:12:26 -0700377 cr, kr, requantization, arch, isa = split_ukernel_name(name)
XNNPACK Teamb455b122019-09-27 18:10:33 -0700378
379 # specification can override architecture
380 arch = ukernel_spec.get("arch", arch)
381
Marat Dukhana5d12612021-05-25 01:12:26 -0700382 test_case = generate_test_cases(
383 name, cr, kr, cr, init_fn, requantization, pipelined, isa)
Marat Dukhan918a4a62019-10-27 19:49:49 -0700384 tests += "\n\n" + xnncommon.postprocess_test_case(test_case, arch, isa, assembly)
XNNPACK Teamb455b122019-09-27 18:10:33 -0700385
386 with codecs.open(options.output, "w", encoding="utf-8") as output_file:
387 output_file.write(tests)
388
389
390if __name__ == "__main__":
391 main(sys.argv[1:])