-
Notifications
You must be signed in to change notification settings - Fork 524
/
Copy pathbackend_details.py
129 lines (103 loc) · 5.18 KB
/
backend_details.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
126
127
128
129
# 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.
from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Dict, List, Optional, Tuple, Union
from executorch.exir._serialize._named_data_store import NamedDataStoreOutput
from executorch.exir.backend.compile_spec_schema import CompileSpec
from torch.export.exported_program import ExportedProgram
def enforcedmethod(func):
func.__enforcedmethod__ = True
return func
@dataclass
class PreprocessResult:
processed_bytes: bytes = bytes()
debug_handle_map: Optional[Union[Dict[int, Tuple[int]], Dict[str, Tuple[int]]]] = (
None
)
# Data Store output created from NamedDataStore.
# Named Data store contains all the named data that is stored in the PTE file,
# but retrieveable by delegates via the NamedDataMap at runtime.
data_store_output: Optional[NamedDataStoreOutput] = None
"""
How to create a backend (for example, BackendWithCompilerDemo):
1. Create a python file, like backend_with_compiler_demo.py, with
a custom class BackendWithCompilerDemo, derived from BackendDetails.
How to use the backend (for example, BackendWithCompilerDemo):
2. Import this class, like
from executorch.exir.backend.backend_with_compiler_demo import BackendWithCompilerDemo
"""
class BackendDetails(ABC):
"""
A base interface to lower the implementation to the according backend. With
the decorators, this interface will be static, abstract and all inheritances are
enforced to implement this method.
"""
@staticmethod
# all backends need to implement this method
@enforcedmethod
# it's a virtual method and inheritant class needs to implement the actual function
@abstractmethod
def preprocess(
edge_program: ExportedProgram,
compile_specs: List[CompileSpec],
) -> PreprocessResult:
"""
Preprocesses an edge program and returns the preprocess result fo the given backend
Args:
edge_program: The original exported program. It will not be modified in place.
compile_specs: List of values needed for compilation
Returns:
PreprocessResult: It wraps the following information:
processed_bytes -> bytes: A compiled blob - a binary that can run the desired
program in the backend.
debug_handle_map (Optional[Dict[int, Tuple[int]]]): For profiling purposes, a
map from the node_id in the final graph (either EXIR or the user's self-defined
IR) to debug handle id attached in the original exported program.
"""
# Users should return a compiled blob - a binary that can run the desired
# program in the backend.
pass
@classmethod
def preprocess_multimethod(
cls,
edge_programs: Dict[str, List[ExportedProgram]],
compile_specs: Dict[str, List[List[CompileSpec]]],
) -> Dict[str, list[PreprocessResult]]:
"""
Runs preprocess on all partitioned Edge Programs across multiple methods. This allows
backends to share information across partitioned graphs. Backend can serialize shared
data by putting the shared data into the data_store_output of the preprocess results.
This will record the shared data used by that specific partition.
Default implementation is running the existing preprocess implementation on all
Args:
edge_programs: Dictionary mapping the method name to a list of all the partitioned
edge_programs from that method to be lowered.
compile_specs: Dictionary mapping the method name to a list of compile_specs. The
list of compile specs maps directly to the list of edge_programs for the
same given method name i.e. edge_program[method_name][i] --> compile_specs[method_name][i]
Returns:
Dictionary mapping the method name to a list of PreprocessResults. The list of
PreprocessResults maps directly to the list of edge_programs for the same given
method name. i.e. edge_program[method_name][i] --> result[method_name][i]
"""
preprocess_results = {}
for method_name, programs in edge_programs.items():
assert (
method_name in compile_specs
), f"Error: missing compile specs for {method_name}"
compile_specs_for_method = compile_specs[method_name]
assert len(compile_specs_for_method) == len(
programs
), f"Error: method {method_name} has {len(programs)} partitions but only {len(compile_specs_for_method)}"
results_for_method = []
for program, compile_spec_for_program in zip(
programs, compile_specs_for_method
):
preprocess_result = cls.preprocess(program, compile_spec_for_program)
results_for_method.append(preprocess_result)
preprocess_results[method_name] = results_for_method
return preprocess_results