| 1138 | } |
| 1139 | |
| 1140 | bool SwappingPass(RewriterConfig::MemOptType optimization_level, |
| 1141 | Cluster* cluster, GrapplerItem* item, |
| 1142 | std::unordered_set<string>* skip_list) { |
| 1143 | std::unordered_map<NodeDef*, SwapInfo> nodes_to_swap; |
| 1144 | if (optimization_level == RewriterConfig::DEFAULT_MEM_OPT || |
| 1145 | optimization_level == RewriterConfig::SWAPPING_HEURISTICS || |
| 1146 | optimization_level == RewriterConfig::HEURISTICS) { |
| 1147 | // Use heuristics to figure out what needs to be swapped; |
| 1148 | IdentifySwappingCandidates(cluster, item, skip_list, &nodes_to_swap); |
| 1149 | } |
| 1150 | // Look for manual annotatations in the graph. |
| 1151 | for (auto& node : *item->graph.mutable_node()) { |
| 1152 | if (node.attr().count("_swap_to_host") != 0) { |
| 1153 | SwapInfo& swap_info = nodes_to_swap[&node]; |
| 1154 | const AttrValue& val = node.attr().at("_swap_to_host"); |
| 1155 | if (val.has_list()) { |
| 1156 | for (int64 input_id : val.list().i()) { |
| 1157 | swap_info.inputs_to_swap.push_back(input_id); |
| 1158 | } |
| 1159 | } else { |
| 1160 | int64 input_id = val.i(); |
| 1161 | swap_info.inputs_to_swap.push_back(input_id); |
| 1162 | } |
| 1163 | } |
| 1164 | } |
| 1165 | if (nodes_to_swap.empty()) { |
| 1166 | // Nothing to do. |
| 1167 | return false; |
| 1168 | } |
| 1169 | |
| 1170 | // Estimate the size of the data to swap for each node. |
| 1171 | GraphProperties properties(*item); |
| 1172 | if (!properties |
| 1173 | .InferStatically(/*assume_valid_feeds=*/true, |
| 1174 | /*aggressive_shape_inference=*/false, |
| 1175 | /*include_tensor_values=*/false) |
| 1176 | .ok()) { |
| 1177 | return false; |
| 1178 | } |
| 1179 | for (auto& swap : nodes_to_swap) { |
| 1180 | const NodeDef* node = swap.first; |
| 1181 | const std::vector<OpInfo::TensorProperties>& props = |
| 1182 | properties.GetInputProperties(node->name()); |
| 1183 | SwapInfo& swap_info = swap.second; |
| 1184 | int64 bytes_to_swap = 0; |
| 1185 | for (int64 input_id : swap_info.inputs_to_swap) { |
| 1186 | const OpInfo::TensorProperties& t = props[input_id]; |
| 1187 | bytes_to_swap += CalculateTensorSize(t); |
| 1188 | } |
| 1189 | // Let's assume we're going to swap over PCIe running at 16 GBps. |
| 1190 | swap_info.time_to_swap = bytes_to_swap / 16; |
| 1191 | } |
| 1192 | |
| 1193 | std::unordered_map<const NodeDef*, Costs::NanoSeconds> execution_times; |
| 1194 | if (!EstimateEarliestExecutionTimes(*item, cluster, &execution_times).ok()) { |
| 1195 | return false; |
| 1196 | } |
| 1197 |
no test coverage detected