cycle_breaker_unittest.cc 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. //
  2. // Copyright (C) 2010 The Android Open Source Project
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. //
  16. #include "update_engine/payload_generator/cycle_breaker.h"
  17. #include <set>
  18. #include <string>
  19. #include <utility>
  20. #include <vector>
  21. #include <base/logging.h>
  22. #include <base/stl_util.h>
  23. #include <gtest/gtest.h>
  24. #include "update_engine/payload_generator/graph_types.h"
  25. using std::make_pair;
  26. using std::pair;
  27. using std::set;
  28. using std::string;
  29. using std::vector;
  30. namespace chromeos_update_engine {
  31. namespace {
  32. void SetOpForNodes(Graph* graph) {
  33. for (Vertex& vertex : *graph) {
  34. vertex.aop.op.set_type(InstallOperation::MOVE);
  35. }
  36. }
  37. } // namespace
  38. class CycleBreakerTest : public ::testing::Test {};
  39. TEST(CycleBreakerTest, SimpleTest) {
  40. int counter = 0;
  41. const Vertex::Index n_a = counter++;
  42. const Vertex::Index n_b = counter++;
  43. const Vertex::Index n_c = counter++;
  44. const Vertex::Index n_d = counter++;
  45. const Vertex::Index n_e = counter++;
  46. const Vertex::Index n_f = counter++;
  47. const Vertex::Index n_g = counter++;
  48. const Vertex::Index n_h = counter++;
  49. const Graph::size_type kNodeCount = counter++;
  50. Graph graph(kNodeCount);
  51. SetOpForNodes(&graph);
  52. graph[n_a].out_edges.insert(make_pair(n_e, EdgeProperties()));
  53. graph[n_a].out_edges.insert(make_pair(n_f, EdgeProperties()));
  54. graph[n_b].out_edges.insert(make_pair(n_a, EdgeProperties()));
  55. graph[n_c].out_edges.insert(make_pair(n_d, EdgeProperties()));
  56. graph[n_d].out_edges.insert(make_pair(n_e, EdgeProperties()));
  57. graph[n_d].out_edges.insert(make_pair(n_f, EdgeProperties()));
  58. graph[n_e].out_edges.insert(make_pair(n_b, EdgeProperties()));
  59. graph[n_e].out_edges.insert(make_pair(n_c, EdgeProperties()));
  60. graph[n_e].out_edges.insert(make_pair(n_f, EdgeProperties()));
  61. graph[n_f].out_edges.insert(make_pair(n_g, EdgeProperties()));
  62. graph[n_g].out_edges.insert(make_pair(n_h, EdgeProperties()));
  63. graph[n_h].out_edges.insert(make_pair(n_g, EdgeProperties()));
  64. CycleBreaker breaker;
  65. set<Edge> broken_edges;
  66. breaker.BreakCycles(graph, &broken_edges);
  67. // The following cycles must be cut:
  68. // A->E->B
  69. // C->D->E
  70. // G->H
  71. EXPECT_TRUE(base::ContainsKey(broken_edges, make_pair(n_a, n_e)) ||
  72. base::ContainsKey(broken_edges, make_pair(n_e, n_b)) ||
  73. base::ContainsKey(broken_edges, make_pair(n_b, n_a)));
  74. EXPECT_TRUE(base::ContainsKey(broken_edges, make_pair(n_c, n_d)) ||
  75. base::ContainsKey(broken_edges, make_pair(n_d, n_e)) ||
  76. base::ContainsKey(broken_edges, make_pair(n_e, n_c)));
  77. EXPECT_TRUE(base::ContainsKey(broken_edges, make_pair(n_g, n_h)) ||
  78. base::ContainsKey(broken_edges, make_pair(n_h, n_g)));
  79. EXPECT_EQ(3U, broken_edges.size());
  80. }
  81. namespace {
  82. pair<Vertex::Index, EdgeProperties> EdgeWithWeight(Vertex::Index dest,
  83. uint64_t weight) {
  84. EdgeProperties props;
  85. props.extents.resize(1);
  86. props.extents[0].set_num_blocks(weight);
  87. return make_pair(dest, props);
  88. }
  89. } // namespace
  90. // This creates a bunch of cycles like this:
  91. //
  92. // root <------.
  93. // (t)-> / | \ |
  94. // V V V |
  95. // N N N |
  96. // \ | / |
  97. // VVV |
  98. // N |
  99. // / | \ |
  100. // V V V |
  101. // N N N |
  102. // ... |
  103. // (s)-> \ | / |
  104. // VVV |
  105. // N |
  106. // \_________/
  107. //
  108. // such that the original cutting algo would cut edges (s). We changed
  109. // the algorithm to cut cycles (t) instead, since they are closer to the
  110. // root, and that can massively speed up cycle cutting.
  111. TEST(CycleBreakerTest, AggressiveCutTest) {
  112. size_t counter = 0;
  113. const int kNodesPerGroup = 4;
  114. const int kGroups = 33;
  115. Graph graph(kGroups * kNodesPerGroup + 1); // + 1 for the root node
  116. SetOpForNodes(&graph);
  117. const Vertex::Index n_root = counter++;
  118. Vertex::Index last_hub = n_root;
  119. for (int i = 0; i < kGroups; i++) {
  120. uint64_t weight = 5;
  121. if (i == 0)
  122. weight = 2;
  123. else if (i == (kGroups - 1))
  124. weight = 1;
  125. const Vertex::Index next_hub = counter++;
  126. for (int j = 0; j < (kNodesPerGroup - 1); j++) {
  127. const Vertex::Index node = counter++;
  128. graph[last_hub].out_edges.insert(EdgeWithWeight(node, weight));
  129. graph[node].out_edges.insert(EdgeWithWeight(next_hub, weight));
  130. }
  131. last_hub = next_hub;
  132. }
  133. graph[last_hub].out_edges.insert(EdgeWithWeight(n_root, 5));
  134. EXPECT_EQ(counter, graph.size());
  135. CycleBreaker breaker;
  136. set<Edge> broken_edges;
  137. LOG(INFO) << "If this hangs for more than 1 second, the test has failed.";
  138. breaker.BreakCycles(graph, &broken_edges);
  139. set<Edge> expected_cuts;
  140. for (Vertex::EdgeMap::const_iterator it = graph[n_root].out_edges.begin(),
  141. e = graph[n_root].out_edges.end();
  142. it != e;
  143. ++it) {
  144. expected_cuts.insert(make_pair(n_root, it->first));
  145. }
  146. EXPECT_TRUE(broken_edges == expected_cuts);
  147. }
  148. TEST(CycleBreakerTest, WeightTest) {
  149. size_t counter = 0;
  150. const Vertex::Index n_a = counter++;
  151. const Vertex::Index n_b = counter++;
  152. const Vertex::Index n_c = counter++;
  153. const Vertex::Index n_d = counter++;
  154. const Vertex::Index n_e = counter++;
  155. const Vertex::Index n_f = counter++;
  156. const Vertex::Index n_g = counter++;
  157. const Vertex::Index n_h = counter++;
  158. const Vertex::Index n_i = counter++;
  159. const Vertex::Index n_j = counter++;
  160. const Graph::size_type kNodeCount = counter++;
  161. Graph graph(kNodeCount);
  162. SetOpForNodes(&graph);
  163. graph[n_a].out_edges.insert(EdgeWithWeight(n_b, 4));
  164. graph[n_a].out_edges.insert(EdgeWithWeight(n_f, 3));
  165. graph[n_a].out_edges.insert(EdgeWithWeight(n_h, 2));
  166. graph[n_b].out_edges.insert(EdgeWithWeight(n_a, 3));
  167. graph[n_b].out_edges.insert(EdgeWithWeight(n_c, 4));
  168. graph[n_c].out_edges.insert(EdgeWithWeight(n_b, 5));
  169. graph[n_c].out_edges.insert(EdgeWithWeight(n_d, 3));
  170. graph[n_d].out_edges.insert(EdgeWithWeight(n_a, 6));
  171. graph[n_d].out_edges.insert(EdgeWithWeight(n_e, 3));
  172. graph[n_e].out_edges.insert(EdgeWithWeight(n_d, 4));
  173. graph[n_e].out_edges.insert(EdgeWithWeight(n_g, 5));
  174. graph[n_f].out_edges.insert(EdgeWithWeight(n_g, 2));
  175. graph[n_g].out_edges.insert(EdgeWithWeight(n_f, 3));
  176. graph[n_g].out_edges.insert(EdgeWithWeight(n_d, 5));
  177. graph[n_h].out_edges.insert(EdgeWithWeight(n_i, 8));
  178. graph[n_i].out_edges.insert(EdgeWithWeight(n_e, 4));
  179. graph[n_i].out_edges.insert(EdgeWithWeight(n_h, 9));
  180. graph[n_i].out_edges.insert(EdgeWithWeight(n_j, 6));
  181. CycleBreaker breaker;
  182. set<Edge> broken_edges;
  183. breaker.BreakCycles(graph, &broken_edges);
  184. // These are required to be broken:
  185. EXPECT_TRUE(base::ContainsKey(broken_edges, make_pair(n_b, n_a)));
  186. EXPECT_TRUE(base::ContainsKey(broken_edges, make_pair(n_b, n_c)));
  187. EXPECT_TRUE(base::ContainsKey(broken_edges, make_pair(n_d, n_e)));
  188. EXPECT_TRUE(base::ContainsKey(broken_edges, make_pair(n_f, n_g)));
  189. EXPECT_TRUE(base::ContainsKey(broken_edges, make_pair(n_h, n_i)));
  190. }
  191. TEST(CycleBreakerTest, UnblockGraphTest) {
  192. size_t counter = 0;
  193. const Vertex::Index n_a = counter++;
  194. const Vertex::Index n_b = counter++;
  195. const Vertex::Index n_c = counter++;
  196. const Vertex::Index n_d = counter++;
  197. const Graph::size_type kNodeCount = counter++;
  198. Graph graph(kNodeCount);
  199. SetOpForNodes(&graph);
  200. graph[n_a].out_edges.insert(EdgeWithWeight(n_b, 1));
  201. graph[n_a].out_edges.insert(EdgeWithWeight(n_c, 1));
  202. graph[n_b].out_edges.insert(EdgeWithWeight(n_c, 2));
  203. graph[n_c].out_edges.insert(EdgeWithWeight(n_b, 2));
  204. graph[n_b].out_edges.insert(EdgeWithWeight(n_d, 2));
  205. graph[n_d].out_edges.insert(EdgeWithWeight(n_a, 2));
  206. CycleBreaker breaker;
  207. set<Edge> broken_edges;
  208. breaker.BreakCycles(graph, &broken_edges);
  209. // These are required to be broken:
  210. EXPECT_TRUE(base::ContainsKey(broken_edges, make_pair(n_a, n_b)));
  211. EXPECT_TRUE(base::ContainsKey(broken_edges, make_pair(n_a, n_c)));
  212. }
  213. TEST(CycleBreakerTest, SkipOpsTest) {
  214. size_t counter = 0;
  215. const Vertex::Index n_a = counter++;
  216. const Vertex::Index n_b = counter++;
  217. const Vertex::Index n_c = counter++;
  218. const Graph::size_type kNodeCount = counter++;
  219. Graph graph(kNodeCount);
  220. SetOpForNodes(&graph);
  221. graph[n_a].aop.op.set_type(InstallOperation::REPLACE_BZ);
  222. graph[n_c].aop.op.set_type(InstallOperation::REPLACE);
  223. graph[n_a].out_edges.insert(EdgeWithWeight(n_b, 1));
  224. graph[n_c].out_edges.insert(EdgeWithWeight(n_b, 1));
  225. CycleBreaker breaker;
  226. set<Edge> broken_edges;
  227. breaker.BreakCycles(graph, &broken_edges);
  228. EXPECT_EQ(2U, breaker.skipped_ops());
  229. }
  230. } // namespace chromeos_update_engine