You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
141 lines
4.6 KiB
141 lines
4.6 KiB
// |
|
// Copyright (C) 2009 The Android Open Source Project |
|
// |
|
// Licensed under the Apache License, Version 2.0 (the "License"); |
|
// you may not use this file except in compliance with the License. |
|
// You may obtain a copy of the License at |
|
// |
|
// http://www.apache.org/licenses/LICENSE-2.0 |
|
// |
|
// Unless required by applicable law or agreed to in writing, software |
|
// distributed under the License is distributed on an "AS IS" BASIS, |
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
// See the License for the specific language governing permissions and |
|
// limitations under the License. |
|
// |
|
|
|
#include "update_engine/payload_generator/graph_utils.h" |
|
|
|
#include <string> |
|
#include <utility> |
|
#include <vector> |
|
|
|
#include <base/logging.h> |
|
#include <base/macros.h> |
|
|
|
#include "update_engine/payload_consumer/payload_constants.h" |
|
#include "update_engine/payload_generator/annotated_operation.h" |
|
#include "update_engine/payload_generator/extent_utils.h" |
|
|
|
using std::make_pair; |
|
using std::pair; |
|
using std::string; |
|
using std::vector; |
|
|
|
namespace chromeos_update_engine { |
|
namespace graph_utils { |
|
|
|
uint64_t EdgeWeight(const Graph& graph, const Edge& edge) { |
|
uint64_t weight = 0; |
|
const vector<Extent>& extents = |
|
graph[edge.first].out_edges.find(edge.second)->second.extents; |
|
for (vector<Extent>::const_iterator it = extents.begin(); |
|
it != extents.end(); ++it) { |
|
if (it->start_block() != kSparseHole) |
|
weight += it->num_blocks(); |
|
} |
|
return weight; |
|
} |
|
|
|
void AddReadBeforeDep(Vertex* src, |
|
Vertex::Index dst, |
|
uint64_t block) { |
|
Vertex::EdgeMap::iterator edge_it = src->out_edges.find(dst); |
|
if (edge_it == src->out_edges.end()) { |
|
// Must create new edge |
|
pair<Vertex::EdgeMap::iterator, bool> result = |
|
src->out_edges.insert(make_pair(dst, EdgeProperties())); |
|
CHECK(result.second); |
|
edge_it = result.first; |
|
} |
|
AppendBlockToExtents(&edge_it->second.extents, block); |
|
} |
|
|
|
void AddReadBeforeDepExtents(Vertex* src, |
|
Vertex::Index dst, |
|
const vector<Extent>& extents) { |
|
// TODO(adlr): Be more efficient than adding each block individually. |
|
for (vector<Extent>::const_iterator it = extents.begin(), e = extents.end(); |
|
it != e; ++it) { |
|
const Extent& extent = *it; |
|
for (uint64_t block = extent.start_block(), |
|
block_end = extent.start_block() + extent.num_blocks(); |
|
block != block_end; ++block) { |
|
AddReadBeforeDep(src, dst, block); |
|
} |
|
} |
|
} |
|
|
|
void DropWriteBeforeDeps(Vertex::EdgeMap* edge_map) { |
|
// Specially crafted for-loop for the map-iterate-delete dance. |
|
for (Vertex::EdgeMap::iterator it = edge_map->begin(); |
|
it != edge_map->end(); ) { |
|
if (!it->second.write_extents.empty()) |
|
it->second.write_extents.clear(); |
|
if (it->second.extents.empty()) { |
|
// Erase *it, as it contains no blocks |
|
edge_map->erase(it++); |
|
} else { |
|
++it; |
|
} |
|
} |
|
} |
|
|
|
// For each node N in graph, drop all edges N->|index|. |
|
void DropIncomingEdgesTo(Graph* graph, Vertex::Index index) { |
|
// This would be much more efficient if we had doubly-linked |
|
// edges in the graph. |
|
for (Graph::iterator it = graph->begin(), e = graph->end(); it != e; ++it) { |
|
it->out_edges.erase(index); |
|
} |
|
} |
|
|
|
namespace { |
|
template<typename T> |
|
void DumpExtents(const T& field, int prepend_space_count) { |
|
string header(prepend_space_count, ' '); |
|
for (int i = 0, e = field.size(); i != e; ++i) { |
|
LOG(INFO) << header << "(" << GetElement(field, i).start_block() << ", " |
|
<< GetElement(field, i).num_blocks() << ")"; |
|
} |
|
} |
|
|
|
void DumpOutEdges(const Vertex::EdgeMap& out_edges) { |
|
for (Vertex::EdgeMap::const_iterator it = out_edges.begin(), |
|
e = out_edges.end(); it != e; ++it) { |
|
LOG(INFO) << " " << it->first << " read-before:"; |
|
DumpExtents(it->second.extents, 6); |
|
LOG(INFO) << " write-before:"; |
|
DumpExtents(it->second.write_extents, 6); |
|
} |
|
} |
|
} // namespace |
|
|
|
void DumpGraph(const Graph& graph) { |
|
LOG(INFO) << "Graph length: " << graph.size(); |
|
for (Graph::size_type i = 0, e = graph.size(); i != e; ++i) { |
|
LOG(INFO) << i |
|
<< (graph[i].valid ? "" : "-INV") |
|
<< ": " << graph[i].aop.name |
|
<< ": " << InstallOperationTypeName(graph[i].aop.op.type()); |
|
LOG(INFO) << " src_extents:"; |
|
DumpExtents(graph[i].aop.op.src_extents(), 4); |
|
LOG(INFO) << " dst_extents:"; |
|
DumpExtents(graph[i].aop.op.dst_extents(), 4); |
|
LOG(INFO) << " out edges:"; |
|
DumpOutEdges(graph[i].out_edges); |
|
} |
|
} |
|
|
|
} // namespace graph_utils |
|
} // namespace chromeos_update_engine
|
|
|