Coverage for /Syzygy/reorder/basic_block_optimizer_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
99.3%2752770.C++test

Line-by-line coverage:

   1    :  // Copyright 2012 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  
  15    :  #include "syzygy/reorder/basic_block_optimizer.h"
  16    :  
  17    :  #include "gmock/gmock.h"
  18    :  #include "gtest/gtest.h"
  19    :  #include "syzygy/block_graph/basic_block_test_util.h"
  20    :  #include "syzygy/block_graph/block_graph.h"
  21    :  #include "syzygy/core/unittest_util.h"
  22    :  #include "syzygy/pe/pe_utils.h"
  23    :  #include "syzygy/reorder/order_generator_test.h"
  24    :  
  25    :  #include "mnemonics.h"  // NOLINT
  26    :  
  27    :  namespace reorder {
  28    :  namespace {
  29    :  
  30    :  using block_graph::BasicBlock;
  31    :  using block_graph::BasicCodeBlock;
  32    :  using block_graph::BasicDataBlock;
  33    :  using block_graph::BlockGraph;
  34    :  using core::RelativeAddress;
  35    :  using grinder::basic_block_util::EntryCountType;
  36    :  using grinder::basic_block_util::IndexedFrequencyInformation;
  37    :  using grinder::basic_block_util::IndexedFrequencyMap;
  38    :  using grinder::basic_block_util::LoadBasicBlockRanges;
  39    :  using grinder::basic_block_util::RelativeAddressRange;
  40    :  using grinder::basic_block_util::RelativeAddressRangeVector;
  41    :  using pe::ImageLayout;
  42    :  using testing::GetExeTestDataRelativePath;
  43    :  
  44    :  typedef Reorderer::Order Order;
  45    :  
  46    :  class TestBasicBlockOrderer : public BasicBlockOptimizer::BasicBlockOrderer {
  47    :   public:
  48    :    using BasicBlockOptimizer::BasicBlockOrderer::GetBasicBlockEntryCount;
  49    :    using BasicBlockOptimizer::BasicBlockOrderer::GetWarmestSuccessor;
  50    :    using BasicBlockOptimizer::BasicBlockOrderer::GetSortedJumpTargets;
  51    :    using BasicBlockOptimizer::BasicBlockOrderer::AddRecursiveDataReferences;
  52    :    using BasicBlockOptimizer::BasicBlockOrderer::AddWarmDataReferences;
  53    :  
  54    :    TestBasicBlockOrderer(
  55    :        const BasicBlockSubGraph& subgraph,
  56    :        const RelativeAddress& addr,
  57    :        Size size,
  58    :        const IndexedFrequencyInformation& entry_counts)
  59  E :            : BasicBlockOptimizer::BasicBlockOrderer(
  60  E :                  subgraph, addr, size, entry_counts) {
  61  E :    }
  62    :  };
  63    :  
  64    :  class BasicBlockOrdererTest : public testing::BasicBlockTest {
  65    :   public:
  66  E :    virtual void SetUp() override {
  67  E :      ASSERT_NO_FATAL_FAILURE(testing::BasicBlockTest::SetUp());
  68  E :      ASSERT_NO_FATAL_FAILURE(InitBlockGraph());
  69  E :      ASSERT_NO_FATAL_FAILURE(InitBasicBlockSubGraph());
  70  E :      ASSERT_NO_FATAL_FAILURE(SetEntryCounts(0, 0, 0, 0, 0, 0, 0, 0));
  71  E :      orderer_.reset(new TestBasicBlockOrderer(subgraph_,
  72    :                                               start_addr_,
  73    :                                               assembly_func_->size(),
  74    :                                               entry_counts_));
  75  E :      ASSERT_TRUE(orderer_.get() != NULL);
  76  E :    }
  77    :  
  78    :    RelativeAddressRange MakeRange(BlockGraph::Offset offset,
  79    :                                   BlockGraph::Size size) {
  80    :      return RelativeAddressRange(start_addr_ + offset, size);
  81    :    }
  82    :  
  83  E :    BasicBlock* FindBasicBlockAt(BlockGraph::Offset offset) {
  84    :      typedef BasicBlockSubGraph::BBCollection BBCollection;
  85    :      BasicBlockSubGraph::BBCollection::iterator it =
  86  E :          subgraph_.basic_blocks().begin();
  87  E :      for (; it != subgraph_.basic_blocks().end(); ++it) {
  88  E :        if ((*it)->offset() == offset)
  89  E :          return *it;
  90  E :      }
  91  i :      return NULL;
  92  E :    }
  93    :  
  94    :    void SetEntryCounts(uint32_t bb0,
  95    :                        uint32_t bb1,
  96    :                        uint32_t bb2,
  97    :                        uint32_t bb3,
  98    :                        uint32_t bb4,
  99    :                        uint32_t bb5,
 100    :                        uint32_t bb6,
 101  E :                        uint32_t bb7) {
 102  E :      entry_counts_.num_entries = kNumCodeBasicBlocks;
 103  E :      entry_counts_.num_columns = 1;
 104  E :      entry_counts_.data_type =
 105    :          ::common::IndexedFrequencyData::BASIC_BLOCK_ENTRY;
 106  E :      entry_counts_.frequency_size = 4;
 107    :  
 108  E :      IndexedFrequencyMap& frequency_map = entry_counts_.frequency_map;
 109  E :      frequency_map.clear();
 110    :  
 111  E :      frequency_map[std::make_pair(start_addr_ + kBasicBlockOffsets[0], 0)] = bb0;
 112  E :      frequency_map[std::make_pair(start_addr_ + kBasicBlockOffsets[1], 0)] = bb1;
 113  E :      frequency_map[std::make_pair(start_addr_ + kBasicBlockOffsets[2], 0)] = bb2;
 114  E :      frequency_map[std::make_pair(start_addr_ + kBasicBlockOffsets[3], 0)] = bb3;
 115  E :      frequency_map[std::make_pair(start_addr_ + kBasicBlockOffsets[4], 0)] = bb4;
 116  E :      frequency_map[std::make_pair(start_addr_ + kBasicBlockOffsets[5], 0)] = bb5;
 117  E :      frequency_map[std::make_pair(start_addr_ + kBasicBlockOffsets[6], 0)] = bb6;
 118  E :      frequency_map[std::make_pair(start_addr_ + kBasicBlockOffsets[7], 0)] = bb7;
 119  E :      ASSERT_EQ(kNumCodeBasicBlocks, frequency_map.size());
 120  E :    }
 121    :  
 122    :    static const size_t kBasicBlockOffsets[kNumCodeBasicBlocks];
 123    :  
 124    :    IndexedFrequencyInformation entry_counts_;
 125    :    std::unique_ptr<TestBasicBlockOrderer> orderer_;
 126    :  };
 127    :  
 128    :  const size_t BasicBlockOrdererTest::kBasicBlockOffsets[kNumCodeBasicBlocks] =
 129    :      { 0, 23, 24, 31, 36, 37, 42, 49 };
 130    :  
 131    :  class BasicBlockOptimizerTest : public testing::OrderGeneratorTest {
 132    :   public:
 133    :    typedef testing::OrderGeneratorTest Super;
 134    :  
 135    :    BasicBlockOptimizerTest()
 136  E :        : num_decomposable_blocks_(0),
 137  E :          num_non_decomposable_blocks_(0),
 138  E :          num_non_code_blocks_(0) {
 139  E :    }
 140    :  
 141  E :    virtual void SetUp() override {
 142  E :      ASSERT_NO_FATAL_FAILURE(Super::SetUp());
 143  E :      ASSERT_NO_FATAL_FAILURE(InitBlockCounts());
 144  E :      base::FilePath pdb_path(GetExeTestDataRelativePath(
 145    :          testing::kBBEntryInstrumentedTestDllPdbName));
 146  E :    }
 147    :  
 148  E :    void InitBlockCounts() {
 149  E :      ASSERT_EQ(0U, num_decomposable_blocks_);
 150  E :      ASSERT_EQ(0U, num_non_decomposable_blocks_);
 151  E :      ASSERT_EQ(0U, num_non_code_blocks_);
 152    :  
 153  E :      for (size_t i = 0; i < image_layout_.sections.size(); ++i) {
 154  E :        const ImageLayout::SectionInfo& section_info = image_layout_.sections[i];
 155    :        BlockGraph::AddressSpace::RangeMapConstIterPair ip =
 156  E :            image_layout_.blocks.GetIntersectingBlocks(section_info.addr,
 157    :                                                       section_info.size);
 158  E :        for (; ip.first != ip.second; ++ip.first) {
 159  E :          const BlockGraph::Block* block = ip.first->second;
 160  E :          if (block->type() != BlockGraph::CODE_BLOCK) {
 161  E :            ++num_non_code_blocks_;
 162  E :          } else if (policy_.BlockIsSafeToBasicBlockDecompose(block)) {
 163  E :            ++num_decomposable_blocks_;
 164  E :          } else {
 165  E :            ++num_non_decomposable_blocks_;
 166    :          }
 167  E :        }
 168  E :      }
 169  E :    }
 170    :  
 171    :    bool FindBlockByName(const base::StringPiece& name,
 172    :                         const BlockGraph::Block** block,
 173  E :                         BlockGraph::AddressSpace::Range* range) {
 174  E :      DCHECK(block != NULL);
 175  E :      DCHECK(range != NULL);
 176    :      BlockGraph::AddressSpace::RangeMapConstIter it =
 177  E :          image_layout_.blocks.begin();
 178  E :      for (; it != image_layout_.blocks.end(); ++it) {
 179  E :        if (it->second->name() == name) {
 180  E :          *range = it->first;
 181  E :          *block = it->second;
 182  E :          return true;
 183    :        }
 184  E :      }
 185  i :      return false;
 186  E :    }
 187    :  
 188    :   protected:
 189    :    pe::PETransformPolicy policy_;
 190    :    BasicBlockOptimizer optimizer_;
 191    :    size_t num_decomposable_blocks_;
 192    :    size_t num_non_decomposable_blocks_;
 193    :    size_t num_non_code_blocks_;
 194    :  };
 195    :  
 196    :  }  // namespace
 197    :  
 198  E :  TEST_F(BasicBlockOrdererTest, GetBlockEntryCount) {
 199  E :    ASSERT_NO_FATAL_FAILURE(SetEntryCounts(1, 0, 1, 5, 1, 0, 0, 0));
 200  E :    EntryCountType entry_count = 0;
 201  E :    EXPECT_TRUE(orderer_->GetBlockEntryCount(&entry_count));
 202  E :    EXPECT_EQ(1U, entry_count);
 203    :  
 204  E :    ASSERT_NO_FATAL_FAILURE(SetEntryCounts(17, 0, 1, 5, 1, 0, 0, 0));
 205  E :    EXPECT_TRUE(orderer_->GetBlockEntryCount(&entry_count));
 206  E :    EXPECT_EQ(17U, entry_count);
 207  E :  }
 208    :  
 209  E :  TEST_F(BasicBlockOrdererTest, GetWarmestSuccessor) {
 210  E :    const BasicCodeBlock* sub = BasicCodeBlock::Cast(FindBasicBlockAt(31));
 211  E :    ASSERT_TRUE(sub != NULL);
 212    :  
 213  E :    const BasicCodeBlock* ret = BasicCodeBlock::Cast(FindBasicBlockAt(36));
 214  E :    ASSERT_TRUE(ret != NULL);
 215    :  
 216  E :    TestBasicBlockOrderer::BasicBlockSet placed_bbs;
 217  E :    const BasicBlock* succ = NULL;
 218    :  
 219    :    // Make the fall-through as the warmest successor.
 220  E :    ASSERT_NO_FATAL_FAILURE(SetEntryCounts(0, 0, 0, 5, 10, 0, 0, 0));
 221  E :    ASSERT_TRUE(orderer_->GetWarmestSuccessor(sub, placed_bbs, &succ));
 222  E :    ASSERT_EQ(ret, succ);
 223    :  
 224    :    // Make the branch taken as the warmest successor.
 225  E :    succ = NULL;
 226  E :    ASSERT_NO_FATAL_FAILURE(SetEntryCounts(0, 0, 0, 10, 5, 0, 0, 0));
 227  E :    ASSERT_TRUE(orderer_->GetWarmestSuccessor(sub, placed_bbs, &succ));
 228  E :    ASSERT_EQ(sub, succ);
 229    :  
 230    :    // Give both branches the same warmth. Should preserve ordering.
 231  E :    succ = NULL;
 232  E :    ASSERT_NO_FATAL_FAILURE(SetEntryCounts(0, 0, 0, 10, 10, 0, 0, 0));
 233  E :    ASSERT_TRUE(orderer_->GetWarmestSuccessor(sub, placed_bbs, &succ));
 234  E :    ASSERT_EQ(ret, succ);
 235    :  
 236    :    // Let the warmest branch already be placed, should return the other branch.
 237  E :    succ = NULL;
 238  E :    placed_bbs.insert(ret);
 239  E :    ASSERT_NO_FATAL_FAILURE(SetEntryCounts(0, 0, 0, 5, 10, 0, 0, 0));
 240  E :    ASSERT_TRUE(orderer_->GetWarmestSuccessor(sub, placed_bbs, &succ));
 241  E :    ASSERT_EQ(sub, succ);
 242    :  
 243    :    // Let the warmest branch already be placed, should return the other branch.
 244    :    // Note that we initialize succ to non NULL to verify that it becomes NULL.
 245  E :    succ = sub;
 246  E :    placed_bbs.insert(sub);
 247  E :    placed_bbs.insert(ret);
 248  E :    ASSERT_NO_FATAL_FAILURE(SetEntryCounts(0, 0, 0, 5, 10, 0, 0, 0));
 249  E :    ASSERT_TRUE(orderer_->GetWarmestSuccessor(sub, placed_bbs, &succ));
 250  E :    ASSERT_EQ(NULL, succ);
 251  E :  }
 252    :  
 253  E :  TEST_F(BasicBlockOrdererTest, AddWarmDataReferences) {
 254    :    // Get basic block pointers to the switch, jump table, and case table.
 255  E :    const BasicCodeBlock* code_bb = BasicCodeBlock::Cast(FindBasicBlockAt(0));
 256  E :    const BasicDataBlock* jump_table = BasicDataBlock::Cast(FindBasicBlockAt(52));
 257  E :    const BasicDataBlock* case_table = BasicDataBlock::Cast(FindBasicBlockAt(64));
 258  E :    ASSERT_TRUE(code_bb != NULL);
 259  E :    ASSERT_TRUE(jump_table != NULL);
 260  E :    ASSERT_TRUE(case_table != NULL);
 261    :  
 262    :    // Capture the references from the switch basic block (offset 0).
 263  E :    TestBasicBlockOrderer::BasicBlockSet references;
 264  E :    ASSERT_TRUE(orderer_->AddWarmDataReferences(code_bb, &references));
 265  E :    EXPECT_EQ(2U, references.size());
 266  E :    EXPECT_EQ(1U, references.count(jump_table));
 267  E :    EXPECT_EQ(1U, references.count(case_table));
 268    :  
 269    :    // Capture the references from the case_0 basic block (offset 24).
 270  E :    references.clear();
 271  E :    code_bb = BasicCodeBlock::Cast(FindBasicBlockAt(24));
 272  E :    ASSERT_TRUE(orderer_->AddWarmDataReferences(code_bb, &references));
 273  E :    EXPECT_TRUE(references.empty());
 274  E :  }
 275    :  
 276  E :  TEST_F(BasicBlockOrdererTest, GetSortedJumpTargets) {
 277  E :    ASSERT_NO_FATAL_FAILURE(SetEntryCounts(0, 0, 2, 0, 0, 1, 3, 0));
 278  E :    const BasicCodeBlock* first_bb = BasicCodeBlock::Cast(FindBasicBlockAt(0));
 279  E :    ASSERT_TRUE(first_bb->successors().empty());
 280  E :    ASSERT_TRUE(!first_bb->instructions().empty());
 281  E :    const block_graph::Instruction& jmp_inst = first_bb->instructions().back();
 282  E :    ASSERT_EQ(I_JMP, jmp_inst.representation().opcode);
 283  E :    logging::SetMinLogLevel(-1);
 284  E :    std::vector<const BasicCodeBlock*> targets;
 285  E :    ASSERT_TRUE(orderer_->GetSortedJumpTargets(jmp_inst, &targets));
 286  E :    ASSERT_THAT(targets,
 287    :                testing::ElementsAre(
 288    :                    BasicCodeBlock::Cast(FindBasicBlockAt(42)),
 289    :                    BasicCodeBlock::Cast(FindBasicBlockAt(24)),
 290  E :                    BasicCodeBlock::Cast(FindBasicBlockAt(37))));
 291  E :  }
 292    :  
 293  E :  TEST_F(BasicBlockOrdererTest, GetStableSortedJumpTargets) {
 294  E :    ASSERT_NO_FATAL_FAILURE(SetEntryCounts(0, 0, 1, 0, 0, 2, 1, 0));
 295  E :    const BasicCodeBlock* first_bb = BasicCodeBlock::Cast(FindBasicBlockAt(0));
 296  E :    ASSERT_TRUE(first_bb->successors().empty());
 297  E :    ASSERT_TRUE(!first_bb->instructions().empty());
 298  E :    const block_graph::Instruction& jmp_inst = first_bb->instructions().back();
 299  E :    ASSERT_EQ(I_JMP, jmp_inst.representation().opcode);
 300  E :    logging::SetMinLogLevel(-1);
 301  E :    std::vector<const BasicCodeBlock*> targets;
 302  E :    ASSERT_TRUE(orderer_->GetSortedJumpTargets(jmp_inst, &targets));
 303  E :    ASSERT_THAT(targets,
 304    :                testing::ElementsAre(
 305    :                    BasicCodeBlock::Cast(FindBasicBlockAt(37)),
 306    :                    BasicCodeBlock::Cast(FindBasicBlockAt(24)),
 307  E :                    BasicCodeBlock::Cast(FindBasicBlockAt(42))));
 308  E :  }
 309    :  
 310  E :  TEST_F(BasicBlockOrdererTest, HotColdSeparation) {
 311  E :    ASSERT_NO_FATAL_FAILURE(SetEntryCounts(1, 0, 1, 5, 1, 0, 0, 0));
 312  E :    Order::OffsetVector warm;
 313  E :    Order::OffsetVector cold;
 314  E :    ASSERT_TRUE(orderer_->GetBasicBlockOrderings(&warm, &cold));
 315    :    // Note that the bb's at 52 and 64 are the jump and case tables, respectively.
 316  E :    EXPECT_THAT(warm, testing::ElementsAre(0, 24, 31, 36, 52, 64));
 317  E :    EXPECT_THAT(cold, testing::ElementsAre(23, 37, 42, 49));
 318  E :  }
 319    :  
 320  E :  TEST_F(BasicBlockOrdererTest, PathStraightening) {
 321    :    // The default control flow of the block we construct isn't very interesting
 322    :    // from a path straightening perspective. So, we modify it here such that the
 323    :    // jnz instruction the end of the basic block at offset 31 branches to case_1
 324    :    // (at offset 37), and then give that basic-block an elevated entry count.
 325  E :    BasicCodeBlock* case_1 = BasicCodeBlock::Cast(FindBasicBlockAt(37));
 326  E :    ASSERT_TRUE(case_1 != NULL);
 327  E :    ASSERT_EQ(1U, case_1->instructions().size());
 328  E :    ASSERT_EQ(I_CALL, case_1->instructions().front().representation().opcode);
 329    :  
 330  E :    BasicCodeBlock* jnz_bb = BasicCodeBlock::Cast(FindBasicBlockAt(31));
 331  E :    ASSERT_TRUE(jnz_bb != NULL);
 332  E :    ASSERT_EQ(1U, jnz_bb->instructions().size());
 333  E :    ASSERT_EQ(I_SUB, jnz_bb->instructions().front().representation().opcode);
 334  E :    ASSERT_EQ(2U, jnz_bb->successors().size());
 335  E :    ASSERT_EQ(block_graph::Successor::kConditionNotEqual,
 336  E :              jnz_bb->successors().front().condition());
 337  E :    jnz_bb->successors().front().set_reference(
 338    :        block_graph::BasicBlockReference(BlockGraph::PC_RELATIVE_REF, 1, case_1));
 339    :  
 340    :    // Setup the entry counts such that the jump table stays in the same order
 341    :    // but case 1 is promoted to follow the jnz basic block.
 342  E :    ASSERT_NO_FATAL_FAILURE(SetEntryCounts(1, 0, 10, 5, 1, 7, 0, 0));
 343  E :    Order::OffsetVector warm;
 344  E :    Order::OffsetVector cold;
 345  E :    ASSERT_TRUE(orderer_->GetBasicBlockOrderings(&warm, &cold));
 346    :    // Note that the bb's at 52 and 64 are the jump and case tables, respectively.
 347  E :    EXPECT_THAT(warm, testing::ElementsAre(0, 24, 31, 37, 36, 52, 64));
 348  E :    EXPECT_THAT(cold, testing::ElementsAre(42, 23, 49));
 349  E :  }
 350    :  
 351  E :  TEST_F(BasicBlockOrdererTest, PathStraighteningAcrossJumpTable) {
 352    :    // Setup the entry counts such that case 1 (at offset 37) is promoted to be
 353    :    // the warmest path through the jump table.
 354  E :    ASSERT_NO_FATAL_FAILURE(SetEntryCounts(1, 0, 1, 5, 1, 7, 0, 0));
 355  E :    Order::OffsetVector warm;
 356  E :    Order::OffsetVector cold;
 357  E :    ASSERT_TRUE(orderer_->GetBasicBlockOrderings(&warm, &cold));
 358    :    // Note that the bb's at 52 and 64 are the jump and case tables, respectively.
 359  E :    EXPECT_THAT(warm, testing::ElementsAre(0, 37, 24, 31, 36, 52, 64));
 360  E :    EXPECT_THAT(cold, testing::ElementsAre(42, 23, 49));
 361  E :  }
 362    :  
 363  E :  TEST_F(BasicBlockOptimizerTest, Accessors) {
 364  E :    const std::string kSectionName(".froboz");
 365  E :    EXPECT_TRUE(!optimizer_.cold_section_name().empty());
 366  E :    EXPECT_NE(kSectionName, optimizer_.cold_section_name());
 367  E :    optimizer_.set_cold_section_name(kSectionName);
 368  E :    EXPECT_EQ(kSectionName, optimizer_.cold_section_name());
 369  E :  }
 370    :  
 371  E :  TEST_F(BasicBlockOptimizerTest, EmptyOrderingAllCold) {
 372  E :    Order order;
 373  E :    IndexedFrequencyInformation entry_counts;
 374  E :    entry_counts.num_entries = 0;
 375  E :    entry_counts.num_columns = 1;
 376  E :    entry_counts.data_type = ::common::IndexedFrequencyData::BASIC_BLOCK_ENTRY;
 377  E :    entry_counts.frequency_size = 4;
 378    :  
 379  E :    ASSERT_TRUE(
 380  E :        optimizer_.Optimize(image_layout_, entry_counts, &order));
 381    :  
 382  E :    EXPECT_EQ(image_layout_.sections.size() + 1, order.sections.size());
 383  E :    EXPECT_EQ(optimizer_.cold_section_name(), order.sections.back().name);
 384  E :    EXPECT_EQ(Order::SectionSpec::kNewSectionId, order.sections.back().id);
 385  E :    EXPECT_EQ(pe::kCodeCharacteristics, order.sections.back().characteristics);
 386    :  
 387    :    // Count the blocks left in the original sections. This should only include
 388    :    // non-code blocks.
 389  E :    size_t num_non_code_blocks = 0;
 390  E :    for (size_t i = 0; i < image_layout_.sections.size(); ++i) {
 391  E :      for (size_t k = 0; k < order.sections[i].blocks.size(); ++k) {
 392  E :        const BlockGraph::Block* block = order.sections[i].blocks[k].block;
 393  E :        ASSERT_TRUE(block != NULL);
 394  E :        ASSERT_NE(BlockGraph::CODE_BLOCK, block->type());
 395  E :        ++num_non_code_blocks;
 396  E :      }
 397  E :    }
 398    :  
 399    :    // Validate that we have the expected numbers of blocks.
 400  E :    EXPECT_EQ(num_non_code_blocks_, num_non_code_blocks);
 401  E :    EXPECT_EQ(num_decomposable_blocks_ + num_non_decomposable_blocks_,
 402  E :              order.sections.back().blocks.size());
 403  E :    for (size_t i = 0; i < order.sections.back().blocks.size(); ++i) {
 404  E :      EXPECT_TRUE(order.sections.back().blocks[i].basic_block_offsets.empty());
 405  E :    }
 406  E :  }
 407    :  
 408  E :  TEST_F(BasicBlockOptimizerTest, HotCold) {
 409    :    // This test does a simple manipulation of the entry counts for DllMain and
 410    :    // validates that some minimum number of its blocks get moved into the cold
 411    :    // section. We defer to the BasicBlockOrdererTest instances above for the
 412    :    // details Hot/Cold and Path Straightening tests.
 413  E :    const BlockGraph::Block* dllmain = NULL;
 414  E :    BlockGraph::AddressSpace::Range range;
 415  E :    ASSERT_TRUE(FindBlockByName("DllMain", &dllmain, &range));
 416  E :    ASSERT_TRUE(dllmain != NULL);
 417    :  
 418    :    using block_graph::BasicBlockSubGraph;
 419    :    using block_graph::BasicBlockDecomposer;
 420    :  
 421  E :    BasicBlockSubGraph subgraph;
 422  E :    BasicBlockDecomposer decomposer(dllmain, &subgraph);
 423  E :    ASSERT_TRUE(decomposer.Decompose());
 424  E :    ASSERT_EQ(1U, subgraph.block_descriptions().size());
 425    :  
 426    :    // Generate an entry count map with a non-zero count for every other BB.
 427  E :    IndexedFrequencyInformation entry_counts;
 428  E :    entry_counts.num_entries = 0;
 429  E :    entry_counts.num_columns = 1;
 430  E :    entry_counts.data_type = ::common::IndexedFrequencyData::BASIC_BLOCK_ENTRY;
 431  E :    entry_counts.frequency_size = 4;
 432  E :    IndexedFrequencyMap& frequency_map = entry_counts.frequency_map;
 433    :  
 434  E :    const BasicBlockSubGraph::BlockDescription& desc =
 435    :        subgraph.block_descriptions().front();
 436    :    BasicBlockSubGraph::BasicBlockOrdering::const_iterator it(
 437  E :        desc.basic_block_order.begin());
 438  E :    size_t num_basic_blocks = desc.basic_block_order.size();
 439  E :    size_t num_hot_blocks = 0;
 440    :  
 441  E :    bool is_hot = true;
 442  E :    BlockGraph::RelativeAddress start_offs = subgraph.original_block()->addr();
 443  E :    for (; it != desc.basic_block_order.end(); ++it) {
 444  E :      if (is_hot && BasicCodeBlock::Cast(*it) != NULL) {
 445  E :        frequency_map[std::make_pair(start_offs + (*it)->offset(), 0)] = 1;
 446  E :        ++num_hot_blocks;
 447    :      }
 448    :  
 449    :      // Toggle hotness for next block.
 450  E :      is_hot = !is_hot;
 451  E :    }
 452    :  
 453    :    // Create an ordering that moves dllmain to a new section.
 454  E :    std::string section_name(".dllmain");
 455  E :    Order order;
 456  E :    order.sections.resize(1);
 457  E :    order.sections[0].id = Order::SectionSpec::kNewSectionId;
 458  E :    order.sections[0].name = section_name;
 459  E :    order.sections[0].characteristics = pe::kCodeCharacteristics;
 460  E :    order.sections[0].blocks.push_back(Order::BlockSpec(dllmain));
 461    :  
 462  E :    ASSERT_TRUE(
 463  E :        optimizer_.Optimize(image_layout_, entry_counts, &order));
 464    :  
 465  E :    ASSERT_EQ(image_layout_.sections.size() + 2, order.sections.size());
 466  E :    ASSERT_EQ(section_name, order.sections[0].name);
 467  E :    ASSERT_EQ(1U, order.sections[0].blocks.size());
 468  E :    ASSERT_TRUE(!order.sections.back().blocks.empty());
 469  E :    ASSERT_EQ(dllmain, order.sections[0].blocks[0].block);
 470  E :    ASSERT_EQ(dllmain, order.sections.back().blocks[0].block);
 471  E :    ASSERT_LE(num_hot_blocks,
 472  E :              order.sections[0].blocks[0].basic_block_offsets.size());
 473    :  
 474    :    // Since data BBs that are referred to by 'hot' code BBs also make
 475    :    // it into the hot BB list, there could be fewer cold blocks than expected.
 476  E :    ASSERT_GE(num_basic_blocks - num_hot_blocks,
 477  E :              order.sections.back().blocks[0].basic_block_offsets.size());
 478  E :  }
 479    :  
 480    :  }  // namespace reorder

Coverage information generated Fri Jul 29 11:00:21 2016.