r""" alloc_graph_input / alloc_graph_output indicates if memory for graph input/output is allocated by the compiler. If not, the runtime will set them using buffers provided by users.
(self)
| 207 | return num_reuse_pairs |
| 208 | |
| 209 | def verify_graph_input_output(self) -> None: |
| 210 | r""" |
| 211 | alloc_graph_input / alloc_graph_output indicates if memory for graph |
| 212 | input/output is allocated by the compiler. If not, the runtime will |
| 213 | set them using buffers provided by users. |
| 214 | """ |
| 215 | graph_module = self.graph_module |
| 216 | # There is one tricky case here. If the graph input and graph output |
| 217 | # tensors have overlap, but alloc_graph_input != alloc_graph_output, |
| 218 | # then the overlapped tensor will cause assertion failure below. |
| 219 | # The current behavior is if either alloc_graph_input or alloc_graph_output |
| 220 | # is false, those overlapped tensor will not have memory allocated. |
| 221 | # |
| 222 | # Ignore the check in this case for now. |
| 223 | overlap = get_graph_input_tensors( |
| 224 | graph_module.graph.nodes, self.graph_signature |
| 225 | ) & get_graph_output_tensors(graph_module.graph.nodes) |
| 226 | if overlap and (self.alloc_graph_input != self.alloc_graph_output): |
| 227 | logging.debug( |
| 228 | "Having overlapping graph input/output tensors while the allocation decision for graph input/output mismatch." |
| 229 | ) |
| 230 | return |
| 231 | |
| 232 | graph_input_allocated = None |
| 233 | graph_output_allocated = None |
| 234 | |
| 235 | has_dynamic_unbound_input = False |
| 236 | has_dynamic_unbound_output = False |
| 237 | |
| 238 | check_list = {"placeholder", "output"} & { |
| 239 | node.op for node in graph_module.graph.nodes |
| 240 | } |
| 241 | assert "output" in check_list, f"graph module has no output: {graph_module}" |
| 242 | |
| 243 | # Collect mutable buffer specs so we can filter them when they appear on |
| 244 | # non-placeholder nodes (e.g., aliased on the output node via SpecPropPass). |
| 245 | mutable_buffer_specs = _get_mutable_buffer_specs( |
| 246 | graph_module.graph.nodes, self.graph_signature |
| 247 | ) |
| 248 | for nd in graph_module.graph.nodes: |
| 249 | if nd.op in check_list: |
| 250 | if not (specs := get_node_tensor_specs(nd)): |
| 251 | continue |
| 252 | if _is_mutable_buffer(nd, self.graph_signature): |
| 253 | continue |
| 254 | specs = list( |
| 255 | filter( |
| 256 | lambda spec: not spec.const |
| 257 | and spec not in mutable_buffer_specs, |
| 258 | specs, |
| 259 | ) |
| 260 | ) |
| 261 | if len(specs) == 0: |
| 262 | # all outputs are const so no need to allocate memory just say we succeeded |
| 263 | graph_output_allocated = self.alloc_graph_output |
| 264 | continue |
| 265 | allocated = any( |
| 266 | spec is None or spec.mem_offset is not None for spec in specs |