27 Updates the Doxygen documentation pages with a table of operators supported by Compute Library.
29 The script builds up a table in XML format internally containing the different operators and their respective supported
30 compute backends, data types and layouts, and the equivalent operator in the Android Neural Networks API. The list of
31 operators is pulled from the OperatorList.h header file and further implementation details are provided in the function
32 headers for the backend-specific operator e.g., NEStridedSlice.h.
35 python update_supported_ops.py
42 from pathlib
import Path
65 operator_list_head_file = self.
project_dir /
"arm_compute" /
"runtime" /
"OperatorList.h"
66 neon_file_name_prefix =
str(self.
project_dir /
"arm_compute" /
"runtime" /
"NEON" /
"functions" /
"NE")
67 cl_file_name_prefix =
str(self.
project_dir /
"arm_compute" /
"runtime" /
"CL" /
"functions" /
"CL")
69 logging.debug(operator_list_head_file)
71 f = open(operator_list_head_file,
'r')
93 r = re.search(
'^\s*/\*\*(.*)', line)
94 if r
and state == States.INIT:
96 if re.search(
'.*\(not ported\)', line):
97 state = States.SKIP_OPERATOR
99 if re.search(
'.*\(only CL\)', line):
100 state = States.SKIP_OPERATOR
102 if re.search(
'.*\(no CL\)', line):
103 state = States.SKIP_OPERATOR
105 if re.search(
'.*\(skip\)', line):
106 state = States.SKIP_OPERATOR
109 r = re.match(
'\s*\*/\s*$', line)
110 if r
and state == States.SKIP_OPERATOR:
114 r = re.match(
'\s*\*\s*$', line)
115 if r
and state == States.SKIP_OPERATOR:
118 r = re.search(
'^\s*\*(.*)', line)
119 if r
and state == States.SKIP_OPERATOR:
123 r = re.search(
'^\s*/\*\*(.*)', line)
124 if r
and state == States.INIT:
126 class_name = tmp.strip()
127 logging.debug(class_name)
131 r = re.search(
'\s*\*\s*Description:\s*', line)
132 if r
and state == States.INIT:
133 state = States.DESCRIPTION
136 r = re.match(
'\s*\*\s*$', line)
137 if r
and state == States.DESCRIPTION:
138 logging.debug(operator_desc)
139 state = States.DESCRIPTION_END
142 r = re.search(
'^\s*\*(.*)', line)
143 if r
and state == States.DESCRIPTION:
145 operator_desc = operator_desc +
' ' + tmp.strip()
149 r = re.search(
'\s*\*\s*Equivalent Android NNAPI Op:\s*', line)
150 if r
and state == States.DESCRIPTION_END:
151 state = States.NN_OPERATOR
154 r = re.match(
'\s*\*\s*$', line)
155 if r
and state == States.NN_OPERATOR:
156 logging.debug(nn_op_list)
157 state = States.NN_OPERATOR_END
159 neon_file_name = neon_file_name_prefix + class_name +
".h"
160 logging.debug(neon_file_name)
162 cl_file_name = cl_file_name_prefix + class_name +
".h"
163 logging.debug(cl_file_name)
165 if Path(neon_file_name).is_file()
and Path(cl_file_name).is_file():
166 if neon_file_name.find(
"NEElementwiseOperations.h") != -1:
167 logging.debug(neon_file_name)
169 elif neon_file_name.find(
"NEElementwiseUnaryLayer.h") != -1:
170 logging.debug(neon_file_name)
178 if neon_file_name.find(
"NELogical.h") != -1:
179 logging.debug(neon_file_name)
183 if Path(neon_file_name).is_file():
185 if Path(cl_file_name).is_file():
190 r = re.search(
'^\s*\*(.*)', line)
191 if r
and state == States.NN_OPERATOR:
194 nn_op_list.append(nn_op)
198 r = re.match(
'\s*\*/\s*$', line)
199 if r
and state == States.NN_OPERATOR_END:
207 logging.debug(file_name)
208 f = open(file_name,
'r')
212 data_layout_list = []
218 r = re.match(
"\s*class\s+(\S+)\s*:\s*(public)*", line)
219 if r
and state == States.INIT:
220 class_name = r.groups()[0]
221 logging.debug(
"class name is %s" % (class_name))
222 state = States.IN_CLASS
225 r = re.match(
"\s*\}\;", line)
226 if r
and state == States.IN_CLASS:
232 r = re.search(
'\s*\*\s*Valid data layouts:', line)
233 if r
and state == States.IN_CLASS:
234 state = States.DATA_LAYOUT_START
237 r = re.match(
'\s*\*\s*$', line)
238 if r
and state == States.DATA_LAYOUT_START:
239 state = States.DATA_LAYOUT_END
242 r = re.search(
'\s*\*\s*\-\s*(.*)', line)
243 if r
and state == States.DATA_LAYOUT_START:
247 data_layout_list.append(tmp)
257 r = re.search(
'\s*\*\s*Valid data type configurations:\s*', line)
258 if r
and state == States.DATA_LAYOUT_END:
259 state = States.DATA_TYPE_START
263 r = re.match(
'\s*\*\s*$', line)
264 if r
and state == States.DATA_TYPE_START:
265 logging.debug(class_name)
266 logging.debug(data_layout_list)
267 logging.debug(io_list)
268 logging.debug(data_type_list)
269 class_no = class_no + 1
271 logging.debug(class_no)
276 data_layout_list = []
279 r = re.search(
'\s*\*(.*)', line)
280 if r
and state == States.DATA_TYPE_START:
283 if re.search(
'\|\:\-\-\-', tmp):
288 if re.search(
'.*(src|input|dst)', tmp):
289 io_list = tmp.split(
'|')
291 data_type = tmp.split(
'|')
292 logging.debug(data_type)
293 data_type_list.append(data_type)
304 tmp +=
" <td rowspan=\"" + rowspan +
"\">" + class_name +
"\n"
305 tmp +=
" <td rowspan=\"" + rowspan +
"\" style=\"width:200px;\">" + operator_desc +
"\n"
306 tmp +=
" <td rowspan=\"" + rowspan +
"\">\n"
308 for item
in nn_op_list:
316 tmp =
" <td>" + class_name +
"\n"
320 for item
in data_layout:
335 for item
in data_type_list:
348 tmp +=
"<caption id=\"multi_row\"></caption>\n"
350 tmp +=
" <th>Function\n"
351 tmp +=
" <th>Description\n"
352 tmp +=
" <th>Equivalent Android NNAPI Op\n"
353 tmp +=
" <th>Backends\n"
354 tmp +=
" <th>Data Layouts\n"
355 tmp +=
" <th>Data Types\n"
359 self.
xml +=
"</table>\n"
365 operator_list_dox = self.
project_dir /
"docs" /
"user_guide" /
"operator_list.dox"
367 with open(operator_list_dox,
"r")
as f:
368 dox_content = f.read()
371 x = re.findall(
"\n<table>", dox_content)
372 y = re.findall(
"\n</table>", dox_content)
373 if len(x) != 1
or len(y) != 1:
374 raise RuntimeError(
"Invalid .dox file")
376 repl_str =
"\n" + self.
xml[:-1]
377 new_file = re.sub(
"\n<table>(.|\n)*\n<\/table>", repl_str, dox_content)
379 with open(operator_list_dox,
"w")
as f:
381 print(
"Successfully updated operator_list.dox with the XML table of supported operators.")
384 if __name__ ==
"__main__":
385 parser = argparse.ArgumentParser(
386 description=
"Updates the Compute Library documentation with a table of supported operators."
393 help=
"Dump the supported operators table XML to stdout",
400 help=
"Enables logging, helpful for debugging. Default: False",
402 args = parser.parse_args()
405 logging.basicConfig(format=
"%(message)s", level=logging.DEBUG)
408 table_xml.generate_table_prefix()
409 table_xml.generate_operator_list()
410 table_xml.generate_table_ending()
411 table_xml.update_dox_file()