-
Notifications
You must be signed in to change notification settings - Fork 524
/
Copy pathmerge_yaml.py
125 lines (105 loc) · 3.88 KB
/
merge_yaml.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree.
import argparse
import os
import sys
from collections import defaultdict
from typing import Any, Dict, List, Optional
import yaml
try:
from yaml import CSafeLoader as Loader
except ImportError:
from yaml import SafeLoader as Loader # type: ignore[misc]
class BlankLineDumper(yaml.SafeDumper):
def write_line_break(self, data=None):
super().write_line_break(data)
# insert a new line between entries.
if len(self.indents) == 1:
super().write_line_break()
def merge(functions_yaml_path: str, fallback_yaml_path: Optional[str], output_dir: str):
output_file = os.path.join(output_dir, "merged.yaml")
def get_canonical_opname(func: object) -> str:
"""get the canonical name of an operator
"op" and "func" are two keywords we are supporting for yaml files.
To give an example:
- op: add.Tensor # mostly used for binding ATen ops to kernels
- func: add.Tensor(Tensor self, Tensor other, Scalar alpha) # mostly used for
defining custom ops.
These two will be supported
Args:
func (object): yaml object
Returns:
str: canonical name of the operator
"""
opname = func["op"] if "op" in func else func["func"].split("(")[0] # type: ignore
if "::" not in opname:
opname = "aten::" + opname
return opname
with open(functions_yaml_path) as f:
functions_obj = yaml.load(f, Loader=Loader)
functions_dict: Dict[str, object] = defaultdict(object)
for func in functions_obj:
functions_dict[get_canonical_opname(func)] = func
if fallback_yaml_path is not None and os.path.exists(fallback_yaml_path):
with open(fallback_yaml_path) as f:
fallback_obj = yaml.load(f, Loader=Loader)
for func in fallback_obj:
opname = get_canonical_opname(func)
if opname not in functions_dict:
functions_dict[opname] = func
with open(output_file, "w") as f:
yaml.dump(
list(functions_dict.values()),
f,
Dumper=BlankLineDumper,
default_flow_style=False,
sort_keys=False,
width=1000,
)
def main(argv: List[Any]) -> None:
"""Merge functions.yaml and fallback yaml. The output yaml will be a union of all entries in functions.yaml and fallback yaml, with operator entries in functions.yaml overriding entries with the same op name in fallback yaml.
E.g.,
functions.yaml:
- op: add.Tensor
- kernel: add_impl
fallback yaml:
- op: add.Tensor
- kernel: add_fallback
- op: relu
- kernel: relu_fallback
Merged:
- op: add.Tensor
- kernel: add_impl
- op: relu
- kernel: relu_fallback
"""
parser = argparse.ArgumentParser(
description="Merge functions.yaml, custom_ops.yaml with fallback yaml, for codegen to consume."
)
parser.add_argument(
"--functions-yaml-path",
"--functions_yaml_path",
help="path to the functions.yaml file to use.",
required=True,
)
parser.add_argument(
"--fallback-yaml-path",
"--fallback_yaml_path",
help="path to fallback yaml file.",
required=False,
)
parser.add_argument(
"--output_dir",
help=("The directory to store the output yaml file"),
required=True,
)
options = parser.parse_args(argv)
assert options.functions_yaml_path is not None and os.path.exists(
options.functions_yaml_path
)
merge(options.functions_yaml_path, options.fallback_yaml_path, options.output_dir)
if __name__ == "__main__":
main(sys.argv[1:])