• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/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(
21    description='IBILINEAR 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.match(r"^xnn_(f16|f32)_ibilinear_chw_ukernel__(.+)_p(\d+)$", name)
31  assert match is not None
32  pixel_tile = int(match.group(3))
33  channel_tile = 1
34
35  arch, isa = xnncommon.parse_target_name(target_name=match.group(2))
36  return channel_tile, pixel_tile, arch, isa
37
38
39IBILINEAR_TEST_TEMPLATE = """\
40TEST(${TEST_NAME}, pixels_eq_${PIXEL_TILE}) {
41  $if ISA_CHECK:
42    ${ISA_CHECK};
43  IBilinearMicrokernelTester()
44    .pixels(${PIXEL_TILE})
45    .channels(${CHANNEL_TILE})
46    .TestCHW(${TEST_FUNC});
47}
48
49$if PIXEL_TILE > 1:
50  TEST(${TEST_NAME}, pixels_div_${PIXEL_TILE}) {
51    $if ISA_CHECK:
52      ${ISA_CHECK};
53    for (size_t pixels = ${PIXEL_TILE*2}; pixels < ${PIXEL_TILE*10}; pixels += ${PIXEL_TILE}) {
54      IBilinearMicrokernelTester()
55        .pixels(pixels)
56        .channels(${CHANNEL_TILE})
57        .TestCHW(${TEST_FUNC});
58    }
59  }
60
61  TEST(${TEST_NAME}, pixels_lt_${PIXEL_TILE}) {
62    $if ISA_CHECK:
63      ${ISA_CHECK};
64    for (size_t pixels = 1; pixels < ${PIXEL_TILE}; pixels++) {
65      IBilinearMicrokernelTester()
66        .pixels(pixels)
67        .channels(${CHANNEL_TILE})
68        .TestCHW(${TEST_FUNC});
69    }
70  }
71
72TEST(${TEST_NAME}, pixels_gt_${PIXEL_TILE}) {
73  $if ISA_CHECK:
74    ${ISA_CHECK};
75  for (size_t pixels = ${PIXEL_TILE+1}; pixels < ${10 if PIXEL_TILE == 1 else PIXEL_TILE*2}; pixels++) {
76    IBilinearMicrokernelTester()
77      .pixels(pixels)
78      .channels(${CHANNEL_TILE})
79      .TestCHW(${TEST_FUNC});
80  }
81}
82
83$if CHANNEL_TILE > 1:
84  TEST(${TEST_NAME}, channels_div_${PIXEL_TILE}) {
85    $if ISA_CHECK:
86      ${ISA_CHECK};
87    for (size_t channels = ${CHANNEL_TILE*2}; channels < ${CHANNEL_TILE*10}; channels += ${CHANNEL_TILE}) {
88      for (size_t pixels = 1; pixels <= ${PIXEL_TILE * 5}; pixels += ${max(1, PIXEL_TILE - 1)}) {
89        IBilinearMicrokernelTester()
90          .pixels(pixels)
91          .channels(channels)
92          .TestCHW(${TEST_FUNC});
93      }
94    }
95  }
96
97TEST(${TEST_NAME}, channels_eq_1) {
98  $if ISA_CHECK:
99    ${ISA_CHECK};
100  for (size_t pixels = 1; pixels <= ${PIXEL_TILE * 5}; pixels += ${max(1, PIXEL_TILE - 1)}) {
101    IBilinearMicrokernelTester()
102      .pixels(pixels)
103      .channels(1)
104      .TestCHW(${TEST_FUNC});
105  }
106}
107
108TEST(${TEST_NAME}, channels_gt_1) {
109  $if ISA_CHECK:
110    ${ISA_CHECK};
111  for (size_t channels = ${CHANNEL_TILE+1}; channels < ${max(CHANNEL_TILE*2, 3)}; channels++) {
112    for (size_t pixels = 1; pixels <= ${PIXEL_TILE * 5}; pixels += ${max(1, PIXEL_TILE - 1)}) {
113      IBilinearMicrokernelTester()
114        .pixels(pixels)
115        .channels(channels)
116        .TestCHW(${TEST_FUNC});
117    }
118  }
119}
120
121TEST(${TEST_NAME}, input_offset) {
122  $if ISA_CHECK:
123    ${ISA_CHECK};
124  for (size_t pixels = 1; pixels < ${PIXEL_TILE * 5}; pixels += ${max(1, PIXEL_TILE - 1)}) {
125    for (size_t channels = 1; channels <= ${CHANNEL_TILE * 5}; channels += ${max(1, CHANNEL_TILE - 1)}) {
126      IBilinearMicrokernelTester()
127        .pixels(pixels)
128        .channels(channels)
129        .input_offset(${next_prime(CHANNEL_TILE * 5 + 1)})
130        .TestCHW(${TEST_FUNC});
131    }
132  }
133}
134
135TEST(${TEST_NAME}, input_stride) {
136  $if ISA_CHECK:
137    ${ISA_CHECK};
138  for (size_t pixels = 1; pixels < ${PIXEL_TILE * 5}; pixels += ${max(1, PIXEL_TILE - 1)}) {
139    for (size_t channels = 1; channels <= ${CHANNEL_TILE * 5}; channels += ${max(1, CHANNEL_TILE - 1)}) {
140      IBilinearMicrokernelTester()
141        .pixels(pixels)
142        .channels(channels)
143        .input_stride(${next_prime(4 * (PIXEL_TILE * 5) + 1)})
144        .TestCHW(${TEST_FUNC});
145    }
146  }
147}
148
149"""
150
151
152def generate_test_cases(ukernel, channel_tile, pixel_tile, isa):
153  """Generates all tests cases for a BILINEAR micro-kernel.
154
155  Args:
156    ukernel: C name of the micro-kernel function.
157    channel_tile: Number of channels processed per one iteration of the inner
158                  loop of the micro-kernel.
159    pixel_tile: Number of pixels processed per one iteration of the outer loop
160                of the micro-kernel.
161    isa: instruction set required to run the micro-kernel. Generated unit test
162         will skip execution if the host processor doesn't support this ISA.
163
164  Returns:
165    Code for the test case.
166  """
167  _, test_name = ukernel.split("_", 1)
168  _, datatype, ukernel_type, _ = ukernel.split("_", 3)
169  test_args = [ukernel]
170  return xngen.preprocess(IBILINEAR_TEST_TEMPLATE, {
171      "TEST_NAME": test_name.upper().replace("UKERNEL_", ""),
172      "TEST_FUNC": ukernel,
173      "UKERNEL_TYPE": ukernel_type.upper(),
174      "DATATYPE": datatype,
175      "CHANNEL_TILE": channel_tile,
176      "PIXEL_TILE": pixel_tile,
177      "ISA_CHECK": xnncommon.generate_isa_check_macro(isa),
178      "next_prime": next_prime,
179  })
180
181
182def main(args):
183  options = parser.parse_args(args)
184
185  with codecs.open(options.spec, "r", encoding="utf-8") as spec_file:
186    spec_yaml = yaml.safe_load(spec_file)
187    if not isinstance(spec_yaml, list):
188      raise ValueError("expected a list of micro-kernels in the spec")
189
190    tests = """\
191// Copyright 2020 Google LLC
192//
193// This source code is licensed under the BSD-style license found in the
194// LICENSE file in the root directory of this source tree.
195//
196// Auto-generated file. Do not edit!
197//   Specification: {specification}
198//   Generator: {generator}
199
200
201#include <gtest/gtest.h>
202
203#include <xnnpack/common.h>
204#include <xnnpack/isa-checks.h>
205
206#include <xnnpack/ibilinear.h>
207#include "ibilinear-microkernel-tester.h"
208""".format(specification=options.spec, generator=sys.argv[0])
209
210    for ukernel_spec in spec_yaml:
211      name = ukernel_spec["name"]
212      channel_tile, pixel_tile, arch, isa = split_ukernel_name(name)
213
214      # specification can override architecture
215      arch = ukernel_spec.get("arch", arch)
216
217      test_case = generate_test_cases(name, channel_tile, pixel_tile, isa)
218      tests += "\n\n" + xnncommon.postprocess_test_case(test_case, arch, isa)
219
220    with codecs.open(options.output, "w", encoding="utf-8") as output_file:
221      output_file.write(tests)
222
223
224if __name__ == "__main__":
225  main(sys.argv[1:])
226