Coverage for /Syzygy/grinder/grinders/sample_grinder_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
100.0%3663660.C++test

Line-by-line coverage:

   1    :  // Copyright 2013 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/grinder/grinders/sample_grinder.h"
  16    :  
  17    :  #include "base/strings/string_util.h"
  18    :  #include "base/strings/utf_string_conversions.h"
  19    :  #include "base/win/scoped_com_initializer.h"
  20    :  #include "gmock/gmock.h"
  21    :  #include "gtest/gtest.h"
  22    :  #include "syzygy/core/unittest_util.h"
  23    :  #include "syzygy/pe/pe_file.h"
  24    :  #include "syzygy/pe/unittest_util.h"
  25    :  #include "syzygy/sampler/unittest_util.h"
  26    :  #include "syzygy/trace/common/clock.h"
  27    :  #include "syzygy/trace/common/unittest_util.h"
  28    :  #include "syzygy/trace/protocol/call_trace_defs.h"
  29    :  
  30    :  namespace grinder {
  31    :  namespace grinders {
  32    :  
  33    :  namespace {
  34    :  
  35    :  const wchar_t kTestDllLabelTestFuncAsm[] =
  36    :      L"syzygy\\pe\\test_dll_label_test_func.asm";
  37    :  
  38    :  // SampleGrinder with some internal details exposed for testing.
  39    :  class TestSampleGrinder : public SampleGrinder {
  40    :   public:
  41    :    // Functions.
  42    :    using SampleGrinder::UpsampleModuleData;
  43    :    using SampleGrinder::IncrementModuleData;
  44    :    using SampleGrinder::IncrementHeatMapFromModuleData;
  45    :    using SampleGrinder::RollUpByName;
  46    :  
  47    :    // Members.
  48    :    using SampleGrinder::aggregation_level_;
  49    :    using SampleGrinder::image_path_;
  50    :    using SampleGrinder::parser_;
  51    :    using SampleGrinder::heat_map_;
  52    :    using SampleGrinder::name_heat_map_;
  53    :    using SampleGrinder::line_info_;
  54    :  };
  55    :  
  56    :  class SampleGrinderTest : public testing::PELibUnitTest {
  57    :   public:
  58    :    SampleGrinderTest()
  59    :        : cmd_line_(base::FilePath(L"sample_grinder.exe")),
  60  E :          sample_data_(NULL) {
  61  E :      trace::common::GetClockInfo(&clock_info_);
  62  E :    }
  63    :  
  64  E :    virtual void SetUp() override {
  65  E :      testing::PELibUnitTest::SetUp();
  66  E :      test_dll_path_ = testing::GetOutputRelativePath(testing::kTestDllName);
  67  E :      ASSERT_TRUE(test_dll_pe_file_.Init(test_dll_path_));
  68  E :      test_dll_pe_file_.GetSignature(&test_dll_pe_sig_);
  69  E :    }
  70    :  
  71  E :    void PrepareDummySampleDataBuffer(size_t bucket_count) {
  72  E :      ASSERT_EQ(0u, buffer_.size());
  73  E :      ASSERT_TRUE(sample_data_ == NULL);
  74    :  
  75    :      buffer_.resize(offsetof(TraceSampleData, buckets) +
  76  E :                         sizeof(uint32) * bucket_count);
  77  E :      sample_data_ = reinterpret_cast<TraceSampleData*>(buffer_.data());
  78  E :    }
  79    :  
  80  E :    void WriteDummySampleData() {
  81  E :      ASSERT_FALSE(test_dll_path_.empty());
  82  E :      ASSERT_TRUE(temp_dir_.empty());
  83  E :      ASSERT_TRUE(trace_file_path_.empty());
  84    :  
  85  E :      this->CreateTemporaryDir(&temp_dir_);
  86    :  
  87  E :      trace_file_path_ = temp_dir_.AppendASCII("sample.bin");
  88  E :      ASSERT_NO_FATAL_FAILURE(testing::WriteDummySamplerTraceFile(
  89    :          trace_file_path_));
  90  E :    }
  91    :  
  92  E :    void InitParser(trace::parser::ParseEventHandlerImpl* handler) {
  93  E :      ASSERT_TRUE(handler != NULL);
  94  E :      ASSERT_TRUE(parser_.Init(handler));
  95  E :      ASSERT_TRUE(parser_.OpenTraceFile(trace_file_path_));
  96  E :    }
  97    :  
  98    :    void GrindSucceeds(SampleGrinder::AggregationLevel aggregation_level,
  99  E :                       bool specify_image) {
 100  E :      TestSampleGrinder g;
 101    :  
 102  E :      if (specify_image)
 103  E :        cmd_line_.AppendSwitchPath(SampleGrinder::kImage, test_dll_path_);
 104    :  
 105    :      cmd_line_.AppendSwitchASCII(
 106    :          SampleGrinder::kAggregationLevel,
 107  E :          SampleGrinder::kAggregationLevelNames[aggregation_level]);
 108  E :      ASSERT_TRUE(g.ParseCommandLine(&cmd_line_));
 109    :  
 110  E :      ASSERT_NO_FATAL_FAILURE(WriteDummySampleData());
 111  E :      ASSERT_NO_FATAL_FAILURE(InitParser(&g));
 112  E :      g.SetParser(&parser_);
 113  E :      ASSERT_TRUE(parser_.Consume());
 114    :  
 115  E :      ASSERT_TRUE(g.Grind());
 116    :  
 117    :      // 1000 samples at a rate of 0.01 samples/sec = 10 seconds of heat.
 118  E :      const double expected_heat = 10.0;
 119  E :      double total_heat = 0;
 120    :  
 121    :      // Check that the output has gone to the right intermediate representation
 122    :      // after grinding. We also check that there was a non-zero amount of
 123    :      // 'heat' distributed.
 124  E :      if (aggregation_level == SampleGrinder::kBasicBlock) {
 125  E :        ASSERT_FALSE(g.heat_map_.empty());
 126  E :        ASSERT_TRUE(g.name_heat_map_.empty());
 127  E :        ASSERT_TRUE(g.line_info_.source_lines().empty());
 128    :  
 129    :        TestSampleGrinder::HeatMap::const_iterator it =
 130  E :            g.heat_map_.begin();
 131  E :        for (; it != g.heat_map_.end(); ++it) {
 132  E :          if (it->second.heat > 0)
 133  E :            LOG(INFO) << ".";
 134  E :          total_heat += it->second.heat;
 135  E :        }
 136    :  
 137  E :        EXPECT_DOUBLE_EQ(expected_heat, total_heat);
 138  E :      } else if (aggregation_level == SampleGrinder::kCompiland ||
 139  E :                 aggregation_level == SampleGrinder::kFunction) {
 140  E :        ASSERT_TRUE(g.heat_map_.empty());
 141  E :        ASSERT_FALSE(g.name_heat_map_.empty());
 142  E :        ASSERT_TRUE(g.line_info_.source_lines().empty());
 143    :  
 144    :        // Look through the NameHeatMap output.
 145  E :        bool compiland_seen = false;
 146  E :        bool function_seen = false;
 147    :        TestSampleGrinder::NameHeatMap::const_iterator it =
 148  E :            g.name_heat_map_.begin();
 149  E :        for (; it != g.name_heat_map_.end(); ++it) {
 150  E :          base::FilePath path(base::UTF8ToWide(*it->first));
 151  E :          if (path.BaseName().value() == L"test_dll_label_test_func.obj")
 152  E :            compiland_seen = true;
 153  E :          if (*it->first == "_LabelTestFunc")
 154  E :            function_seen = true;
 155  E :          if (it->second > 0)
 156  E :            LOG(INFO) << ".";
 157  E :          total_heat += it->second;
 158  E :        }
 159    :  
 160  E :        if (aggregation_level == SampleGrinder::kCompiland) {
 161  E :          EXPECT_TRUE(compiland_seen);
 162  E :          EXPECT_FALSE(function_seen);
 163  E :        } else {
 164  E :          EXPECT_FALSE(compiland_seen);
 165  E :          EXPECT_TRUE(function_seen);
 166    :        }
 167  E :      } else {
 168  E :        ASSERT_EQ(SampleGrinder::kLine, aggregation_level);
 169  E :        ASSERT_TRUE(g.heat_map_.empty());
 170  E :        ASSERT_TRUE(g.name_heat_map_.empty());
 171  E :        ASSERT_FALSE(g.line_info_.source_lines().empty());
 172    :  
 173    :        // Get the path to the source file where all of the heat should land.
 174    :        base::FilePath source_file_path =
 175  E :            testing::GetSrcRelativePath(kTestDllLabelTestFuncAsm);
 176  E :        std::string source_file = base::WideToUTF8(source_file_path.value());
 177    :  
 178    :        // All of the heat is in the first 4-byte bucket of the LabelTestFunc.
 179    :        // Thus, it will be spread evenly across the source ranges in those 4
 180    :        // bytes, with the lowest value scaled to 1. The scaling makes the visit
 181    :        // count the same as the encoded instruction size.
 182    :        typedef std::map<size_t, uint32> LineVisitCountMap;
 183  E :        LineVisitCountMap expected, actual;
 184  E :        expected[61] = 1;  // Label. Ends up being a 1 byte source range.
 185  E :        expected[64] = 1;  // push ebp (1 byte).
 186  E :        expected[65] = 2;  // mov ebp, esp (2 bytes).
 187  E :        expected[66] = 1;  // push ecx (1 byte).
 188    :  
 189  E :        uint32 min_visit_count = 0xFFFFFFFF;
 190  E :        for (size_t i = 0; i < g.line_info_.source_lines().size(); ++i) {
 191  E :          const LineInfo::SourceLine& line = g.line_info_.source_lines()[i];
 192  E :          if (line.visit_count == 0)
 193  E :            continue;
 194    :  
 195  E :          if (line.visit_count < min_visit_count)
 196  E :            min_visit_count = line.visit_count;
 197    :  
 198  E :          EXPECT_EQ(base::ToLowerASCII(source_file),
 199    :                    base::ToLowerASCII(*line.source_file_name));
 200  E :          actual[line.line_number] = line.visit_count;
 201  E :        }
 202  E :        EXPECT_EQ(1u, min_visit_count);
 203    :  
 204  E :        EXPECT_THAT(expected, testing::ContainerEq(actual));
 205    :  
 206    :        // We can't say anything concrete about the total heat, as it has been
 207    :        // scaled such that the smallest non-zero value is a 1.
 208  E :        total_heat = 10.0;
 209  E :      }
 210  E :      EXPECT_DOUBLE_EQ(10.0, total_heat);
 211    :  
 212    :      // Produce the output.
 213  E :      base::FilePath csv_path = temp_dir_.Append(L"output.csv");
 214  E :      base::ScopedFILE csv_file(base::OpenFile(csv_path, "wb"));
 215  E :      ASSERT_TRUE(csv_file.get() != NULL);
 216  E :      ASSERT_TRUE(g.OutputData(csv_file.get()));
 217  E :      csv_file.reset();
 218    :  
 219    :      // Ensure output was produced.
 220  E :      int64 file_size = 0;
 221  E :      ASSERT_TRUE(base::GetFileSize(csv_path, &file_size));
 222  E :      ASSERT_LT(0u, file_size);
 223  E :    }
 224    :  
 225    :    // Ensures that COM is initialized for tests in this fixture.
 226    :    base::win::ScopedCOMInitializer com_initializer_;
 227    :  
 228    :    base::FilePath test_dll_path_;
 229    :    pe::PEFile test_dll_pe_file_;
 230    :    pe::PEFile::Signature test_dll_pe_sig_;
 231    :  
 232    :    base::FilePath temp_dir_;
 233    :    base::FilePath trace_file_path_;
 234    :  
 235    :    base::CommandLine cmd_line_;
 236    :    trace::parser::Parser parser_;
 237    :  
 238    :    std::vector<uint8> buffer_;
 239    :    TraceSampleData* sample_data_;
 240    :  
 241    :    trace::common::ClockInfo clock_info_;
 242    :  };
 243    :  
 244  E :  double BucketSum(const SampleGrinder::ModuleData& module_data) {
 245  E :    double sum = 0;
 246  E :    for (size_t i = 0; i < module_data.buckets.size(); ++i)
 247  E :      sum += module_data.buckets[i];
 248  E :    return sum;
 249  E :  }
 250    :  
 251    :  }  // namespace
 252    :  
 253  E :  TEST_F(SampleGrinderTest, UpsampleModuleData) {
 254  E :    SampleGrinder::ModuleData module_data;
 255  E :    EXPECT_EQ(0u, module_data.buckets.size());
 256  E :    EXPECT_EQ(0u, module_data.bucket_size);
 257    :  
 258    :    // UpsampleModuleData only cares about bucket_size and bucket_count, so no
 259    :    // need to worry about filling out a full TraceSampleData object.
 260  E :    TraceSampleData sample_data = {};
 261  E :    sample_data.bucket_count = 1000;
 262  E :    sample_data.bucket_size = 8;
 263  E :    TestSampleGrinder::UpsampleModuleData(&sample_data, &module_data);
 264  E :    ASSERT_EQ(1000u, module_data.buckets.size());
 265  E :    EXPECT_EQ(8u, module_data.bucket_size);
 266  E :    module_data.buckets[0] = 2.0;
 267  E :    EXPECT_DOUBLE_EQ(2.0, BucketSum(module_data));
 268    :  
 269  E :    TestSampleGrinder::UpsampleModuleData(&sample_data, &module_data);
 270  E :    ASSERT_EQ(1000u, module_data.buckets.size());
 271  E :    EXPECT_EQ(8u, module_data.bucket_size);
 272  E :    EXPECT_DOUBLE_EQ(2.0, module_data.buckets[0]);
 273  E :    EXPECT_DOUBLE_EQ(2.0, BucketSum(module_data));
 274    :  
 275  E :    sample_data.bucket_count = 500;
 276  E :    sample_data.bucket_size = 16;
 277  E :    TestSampleGrinder::UpsampleModuleData(&sample_data, &module_data);
 278  E :    ASSERT_EQ(1000u, module_data.buckets.size());
 279  E :    EXPECT_EQ(8u, module_data.bucket_size);
 280  E :    EXPECT_DOUBLE_EQ(2.0, module_data.buckets[0]);
 281  E :    EXPECT_DOUBLE_EQ(2.0, BucketSum(module_data));
 282    :  
 283  E :    sample_data.bucket_count = 2000;
 284  E :    sample_data.bucket_size = 4;
 285  E :    TestSampleGrinder::UpsampleModuleData(&sample_data, &module_data);
 286  E :    ASSERT_EQ(2000u, module_data.buckets.size());
 287  E :    EXPECT_EQ(4u, module_data.bucket_size);
 288  E :    EXPECT_DOUBLE_EQ(1.0, module_data.buckets[0]);
 289  E :    EXPECT_DOUBLE_EQ(1.0, module_data.buckets[1]);
 290  E :    EXPECT_DOUBLE_EQ(2.0, BucketSum(module_data));
 291  E :  }
 292    :  
 293  E :  TEST_F(SampleGrinderTest, IncrementModuleData) {
 294  E :    ASSERT_NO_FATAL_FAILURE(PrepareDummySampleDataBuffer(5));
 295  E :    ASSERT_TRUE(sample_data_ != NULL);
 296    :  
 297    :    // We make our sampling interval 1/10th of the clock rate, so that each
 298    :    // sample is worth 0.1 'seconds'.
 299  E :    uint64 sampling_interval = clock_info_.tsc_info.frequency / 10;
 300  E :    uint32 bucket_start = 0x00011000;
 301    :  
 302  E :    sample_data_->module_base_addr = reinterpret_cast<ModuleAddr>(0x00100000);
 303  E :    sample_data_->module_size = 0x00010000;
 304  E :    sample_data_->module_checksum = 0xAAAAAAAA;
 305  E :    sample_data_->module_time_date_stamp = 0xBBBBBBBB;
 306  E :    sample_data_->bucket_size = 8;
 307  E :    sample_data_->bucket_start = reinterpret_cast<ModuleAddr>(bucket_start);
 308  E :    sample_data_->bucket_count = 5;
 309  E :    sample_data_->sampling_start_time = 0;
 310  E :    sample_data_->sampling_end_time = sampling_interval * 5;
 311  E :    sample_data_->sampling_interval = sampling_interval;
 312  E :    sample_data_->buckets[0] = 3;
 313  E :    sample_data_->buckets[1] = 1;
 314  E :    sample_data_->buckets[2] = 1;
 315    :  
 316  E :    SampleGrinder::ModuleData module_data;
 317  E :    module_data.bucket_start.set_value(bucket_start);
 318  E :    TestSampleGrinder::UpsampleModuleData(sample_data_, &module_data);
 319  E :    ASSERT_EQ(sample_data_->bucket_count, module_data.buckets.size());
 320    :  
 321    :    // If the bucket starts aren't aligned this should fail.
 322  E :    module_data.bucket_start -= 4;
 323    :    EXPECT_FALSE(TestSampleGrinder::IncrementModuleData(
 324  E :        clock_info_.tsc_info.frequency, sample_data_, &module_data));
 325  E :    module_data.bucket_start += 4;
 326    :  
 327    :    // If the bucket lengths aren't consistent this should also fail.
 328  E :    module_data.buckets.resize(sample_data_->bucket_count - 1);
 329    :    EXPECT_FALSE(TestSampleGrinder::IncrementModuleData(
 330  E :        clock_info_.tsc_info.frequency, sample_data_, &module_data));
 331  E :    module_data.buckets.resize(sample_data_->bucket_count);
 332    :  
 333    :    // If the bucket length and start are consistent, then this should pass.
 334    :    EXPECT_TRUE(TestSampleGrinder::IncrementModuleData(
 335  E :        clock_info_.tsc_info.frequency, sample_data_, &module_data));
 336  E :    EXPECT_EQ(8u, module_data.bucket_size);
 337  E :    EXPECT_EQ(5u, module_data.buckets.size());
 338  E :    EXPECT_DOUBLE_EQ(0.3, module_data.buckets[0]);
 339  E :    EXPECT_DOUBLE_EQ(0.1, module_data.buckets[1]);
 340  E :    EXPECT_DOUBLE_EQ(0.1, module_data.buckets[2]);
 341  E :    EXPECT_DOUBLE_EQ(0.5, BucketSum(module_data));
 342    :  
 343    :    // Adding more of the same should work.
 344    :    EXPECT_TRUE(TestSampleGrinder::IncrementModuleData(
 345  E :        clock_info_.tsc_info.frequency, sample_data_, &module_data));
 346  E :    EXPECT_EQ(8u, module_data.bucket_size);
 347  E :    EXPECT_EQ(5u, module_data.buckets.size());
 348  E :    EXPECT_DOUBLE_EQ(0.6, module_data.buckets[0]);
 349  E :    EXPECT_DOUBLE_EQ(0.2, module_data.buckets[1]);
 350  E :    EXPECT_DOUBLE_EQ(0.2, module_data.buckets[2]);
 351  E :    EXPECT_DOUBLE_EQ(1.0, BucketSum(module_data));
 352    :  
 353    :    // Adding larger buckets should see the values split across the finer
 354    :    // resolution aggregated buckets.
 355  E :    sample_data_->bucket_count = 3;
 356  E :    sample_data_->bucket_size = 16;
 357  E :    sample_data_->buckets[0] = 2;
 358  E :    sample_data_->buckets[1] = 0;
 359  E :    sample_data_->buckets[2] = 0;
 360    :    EXPECT_TRUE(TestSampleGrinder::IncrementModuleData(
 361  E :        clock_info_.tsc_info.frequency, sample_data_, &module_data));
 362  E :    EXPECT_EQ(8u, module_data.bucket_size);
 363  E :    EXPECT_EQ(5u, module_data.buckets.size());
 364  E :    EXPECT_DOUBLE_EQ(0.7, module_data.buckets[0]);
 365  E :    EXPECT_DOUBLE_EQ(0.3, module_data.buckets[1]);
 366  E :    EXPECT_DOUBLE_EQ(0.2, module_data.buckets[2]);
 367  E :    EXPECT_DOUBLE_EQ(1.2, BucketSum(module_data));
 368  E :  }
 369    :  
 370  E :  TEST_F(SampleGrinderTest, IncrementHeatMapFromModuleData) {
 371    :    // Make 9 buckets, each with 1 second of samples in them.
 372  E :    SampleGrinder::ModuleData module_data;
 373  E :    module_data.bucket_size = 4;
 374  E :    module_data.buckets.resize(9, 1.0);
 375    :  
 376    :    // RVA    : 0     4     8     12    16    20    24    28    32    36
 377    :    // Buckets: |--0--|--1--|--2--|--3--|--4--|--5--|--6--|--7--|--8--|
 378    :    // Ranges : |--A--|B|       |C| |D| |E |F |  |--G--|  |H| |I|
 379    :    // A perfectly spans a bucket.
 380    :    // B aligns with the left edge of a bucket, but claims all of it.
 381    :    // C aligns with the right edge of a bucket, but claims all of it.
 382    :    // D is in the middle of a bucket and claims all of it.
 383    :    // E and F share a bucket, covering all of it.
 384    :    // G spans 2 buckets.
 385    :    // H and I share a bucket, but don't cover it entirely.
 386    :  
 387    :    typedef SampleGrinder::BasicBlockData BasicBlockData;
 388    :    typedef SampleGrinder::HeatMap HeatMap;
 389    :    typedef SampleGrinder::HeatMap::AddressSpace::Range Range;
 390    :    typedef SampleGrinder::HeatMap::AddressSpace::Range::Address RVA;
 391    :  
 392  E :    HeatMap heat_map;
 393  E :    const BasicBlockData kData = {};
 394  E :    ASSERT_TRUE(heat_map.Insert(Range(RVA(0), 4), kData));  // A.
 395  E :    ASSERT_TRUE(heat_map.Insert(Range(RVA(4), 2), kData));  // B.
 396  E :    ASSERT_TRUE(heat_map.Insert(Range(RVA(10), 2), kData));  // C.
 397  E :    ASSERT_TRUE(heat_map.Insert(Range(RVA(13), 2), kData));  // D.
 398  E :    ASSERT_TRUE(heat_map.Insert(Range(RVA(16), 2), kData));  // E.
 399  E :    ASSERT_TRUE(heat_map.Insert(Range(RVA(18), 2), kData));  // F.
 400  E :    ASSERT_TRUE(heat_map.Insert(Range(RVA(22), 4), kData));  // G.
 401  E :    ASSERT_TRUE(heat_map.Insert(Range(RVA(28), 1), kData));  // H.
 402  E :    ASSERT_TRUE(heat_map.Insert(Range(RVA(31), 1), kData));  // I.
 403    :  
 404  E :    double total_samples = 0;
 405    :    double orphaned_samples = TestSampleGrinder::IncrementHeatMapFromModuleData(
 406  E :        module_data, &heat_map, &total_samples);
 407  E :    EXPECT_DOUBLE_EQ(1.0, orphaned_samples);
 408  E :    EXPECT_DOUBLE_EQ(9.0, total_samples);
 409    :  
 410    :    // We expect the heat to have been distributed to the ranges in the following
 411    :    // quantities.
 412    :    const double kHeat[] = { /* A */ 1.0, /* B */ 1.0, /* C */ 1.0,
 413    :                             /* D */ 1.0, /* E */ 0.5, /* F */ 0.5,
 414  E :                             /* G */ 2.0, /* H */ 0.5, /* I */ 0.5 };
 415  E :    ASSERT_EQ(arraysize(kHeat), heat_map.size());
 416  E :    HeatMap::const_iterator it = heat_map.begin();
 417  E :    for (size_t i = 0; it != heat_map.end(); ++it, ++i)
 418  E :      EXPECT_DOUBLE_EQ(kHeat[i], it->second.heat);
 419  E :  }
 420    :  
 421  E :  TEST_F(SampleGrinderTest, RollUpByName) {
 422  E :    const std::string kFoo = "foo";
 423  E :    const std::string kBar = "bar";
 424    :  
 425    :    typedef TestSampleGrinder::HeatMap::AddressSpace::Range Range;
 426    :    typedef TestSampleGrinder::HeatMap::AddressSpace::Range::Address RVA;
 427    :  
 428    :    // Create a very simple heat map.
 429  E :    TestSampleGrinder::HeatMap heat_map;
 430  E :    TestSampleGrinder::BasicBlockData bbd0 = { &kFoo, &kBar, 1.0 };
 431  E :    TestSampleGrinder::BasicBlockData bbd1 = { &kBar, &kFoo, 2.0 };
 432  E :    ASSERT_TRUE(heat_map.Insert(Range(RVA(0), 4), bbd0));
 433  E :    ASSERT_TRUE(heat_map.Insert(Range(RVA(4), 4), bbd1));
 434    :  
 435  E :    TestSampleGrinder::NameHeatMap nhm;
 436  E :    TestSampleGrinder::NameHeatMap expected_nhm;
 437    :  
 438  E :    expected_nhm[&kFoo] = 2.0;
 439  E :    expected_nhm[&kBar] = 1.0;
 440  E :    TestSampleGrinder::RollUpByName(SampleGrinder::kFunction, heat_map, &nhm);
 441  E :    EXPECT_THAT(nhm, testing::ContainerEq(expected_nhm));
 442    :  
 443  E :    nhm.clear();
 444  E :    expected_nhm[&kFoo] = 1.0;
 445  E :    expected_nhm[&kBar] = 2.0;
 446  E :    TestSampleGrinder::RollUpByName(SampleGrinder::kCompiland, heat_map, &nhm);
 447  E :    EXPECT_THAT(nhm, testing::ContainerEq(expected_nhm));
 448  E :  }
 449    :  
 450  E :  TEST_F(SampleGrinderTest, ParseEmptyCommandLineFails) {
 451  E :    TestSampleGrinder g;
 452  E :    EXPECT_FALSE(g.ParseCommandLine(&cmd_line_));
 453  E :  }
 454    :  
 455  E :  TEST_F(SampleGrinderTest, ParseMinimalCommandLineSucceeds) {
 456  E :    TestSampleGrinder g;
 457  E :    cmd_line_.AppendSwitchPath(SampleGrinder::kImage, test_dll_path_);
 458  E :    EXPECT_TRUE(g.ParseCommandLine(&cmd_line_));
 459  E :    EXPECT_EQ(test_dll_path_, g.image_path_);
 460  E :    EXPECT_EQ(SampleGrinder::kBasicBlock, g.aggregation_level_);
 461  E :  }
 462    :  
 463  E :  TEST_F(SampleGrinderTest, ParseCommandLineAggregationLevel) {
 464    :    // Test command line without specifying '--image'.
 465    :  
 466  E :    cmd_line_.AppendSwitchASCII(SampleGrinder::kAggregationLevel, "basic-block");
 467    :    {
 468  E :      TestSampleGrinder g;
 469  E :      EXPECT_FALSE(g.ParseCommandLine(&cmd_line_));
 470  E :    }
 471    :  
 472  E :    cmd_line_.Init(0, NULL);
 473  E :    cmd_line_.AppendSwitchASCII(SampleGrinder::kAggregationLevel, "function");
 474    :    {
 475  E :      TestSampleGrinder g;
 476  E :      EXPECT_TRUE(g.ParseCommandLine(&cmd_line_));
 477  E :      EXPECT_TRUE(g.image_path_.empty());
 478  E :      EXPECT_EQ(SampleGrinder::kFunction, g.aggregation_level_);
 479  E :    }
 480    :  
 481  E :    cmd_line_.Init(0, NULL);
 482  E :    cmd_line_.AppendSwitchASCII(SampleGrinder::kAggregationLevel, "compiland");
 483    :    {
 484  E :      TestSampleGrinder g;
 485  E :      EXPECT_TRUE(g.ParseCommandLine(&cmd_line_));
 486  E :      EXPECT_TRUE(g.image_path_.empty());
 487  E :      EXPECT_EQ(SampleGrinder::kCompiland, g.aggregation_level_);
 488  E :    }
 489    :  
 490  E :    cmd_line_.Init(0, NULL);
 491  E :    cmd_line_.AppendSwitchASCII(SampleGrinder::kAggregationLevel, "line");
 492    :    {
 493  E :      TestSampleGrinder g;
 494  E :      EXPECT_TRUE(g.ParseCommandLine(&cmd_line_));
 495  E :      EXPECT_TRUE(g.image_path_.empty());
 496  E :      EXPECT_EQ(SampleGrinder::kLine, g.aggregation_level_);
 497  E :    }
 498    :  
 499  E :    cmd_line_.Init(0, NULL);
 500  E :    cmd_line_.AppendSwitchASCII(SampleGrinder::kAggregationLevel, "foobar");
 501    :    {
 502  E :      TestSampleGrinder g;
 503  E :      EXPECT_FALSE(g.ParseCommandLine(&cmd_line_));
 504  E :    }
 505    :  
 506    :    // Test command line when specifying '--image'.
 507    :  
 508  E :    cmd_line_.Init(0, NULL);
 509  E :    cmd_line_.AppendSwitchPath(SampleGrinder::kImage, test_dll_path_);
 510  E :    cmd_line_.AppendSwitchASCII(SampleGrinder::kAggregationLevel, "basic-block");
 511    :    {
 512  E :      TestSampleGrinder g;
 513  E :      EXPECT_TRUE(g.ParseCommandLine(&cmd_line_));
 514  E :      EXPECT_EQ(test_dll_path_, g.image_path_);
 515  E :      EXPECT_EQ(SampleGrinder::kBasicBlock, g.aggregation_level_);
 516  E :    }
 517    :  
 518  E :    cmd_line_.Init(0, NULL);
 519  E :    cmd_line_.AppendSwitchPath(SampleGrinder::kImage, test_dll_path_);
 520  E :    cmd_line_.AppendSwitchASCII(SampleGrinder::kAggregationLevel, "function");
 521    :    {
 522  E :      TestSampleGrinder g;
 523  E :      EXPECT_TRUE(g.ParseCommandLine(&cmd_line_));
 524  E :      EXPECT_EQ(test_dll_path_, g.image_path_);
 525  E :      EXPECT_EQ(SampleGrinder::kFunction, g.aggregation_level_);
 526  E :    }
 527    :  
 528  E :    cmd_line_.Init(0, NULL);
 529  E :    cmd_line_.AppendSwitchPath(SampleGrinder::kImage, test_dll_path_);
 530  E :    cmd_line_.AppendSwitchASCII(SampleGrinder::kAggregationLevel, "line");
 531    :    {
 532  E :      TestSampleGrinder g;
 533  E :      EXPECT_TRUE(g.ParseCommandLine(&cmd_line_));
 534  E :      EXPECT_EQ(test_dll_path_, g.image_path_);
 535  E :      EXPECT_EQ(SampleGrinder::kLine, g.aggregation_level_);
 536  E :    }
 537    :  
 538  E :    cmd_line_.Init(0, NULL);
 539  E :    cmd_line_.AppendSwitchPath(SampleGrinder::kImage, test_dll_path_);
 540  E :    cmd_line_.AppendSwitchASCII(SampleGrinder::kAggregationLevel, "compiland");
 541    :    {
 542  E :      TestSampleGrinder g;
 543  E :      EXPECT_TRUE(g.ParseCommandLine(&cmd_line_));
 544  E :      EXPECT_EQ(test_dll_path_, g.image_path_);
 545  E :      EXPECT_EQ(SampleGrinder::kCompiland, g.aggregation_level_);
 546  E :    }
 547    :  
 548  E :    cmd_line_.Init(0, NULL);
 549  E :    cmd_line_.AppendSwitchPath(SampleGrinder::kImage, test_dll_path_);
 550  E :    cmd_line_.AppendSwitchASCII(SampleGrinder::kAggregationLevel, "foobar");
 551    :    {
 552  E :      TestSampleGrinder g;
 553  E :      EXPECT_FALSE(g.ParseCommandLine(&cmd_line_));
 554  E :    }
 555  E :  }
 556    :  
 557  E :  TEST_F(SampleGrinderTest, SetParserSucceeds) {
 558  E :    TestSampleGrinder g;
 559  E :    EXPECT_TRUE(g.parser_ == NULL);
 560    :  
 561  E :    g.SetParser(&parser_);
 562  E :    EXPECT_EQ(&parser_, g.parser_);
 563  E :  }
 564    :  
 565  E :  TEST_F(SampleGrinderTest, GrindBasicBlock) {
 566  E :    TestSampleGrinder g;
 567  E :    ASSERT_NO_FATAL_FAILURE(GrindSucceeds(SampleGrinder::kBasicBlock, true));
 568  E :  }
 569    :  
 570  E :  TEST_F(SampleGrinderTest, GrindFunction) {
 571  E :    TestSampleGrinder g;
 572  E :    ASSERT_NO_FATAL_FAILURE(GrindSucceeds(SampleGrinder::kFunction, true));
 573  E :  }
 574    :  
 575  E :  TEST_F(SampleGrinderTest, GrindFunctionNoImageSpecified) {
 576  E :    TestSampleGrinder g;
 577  E :    ASSERT_NO_FATAL_FAILURE(GrindSucceeds(SampleGrinder::kFunction, false));
 578  E :  }
 579    :  
 580  E :  TEST_F(SampleGrinderTest, GrindCompiland) {
 581  E :    TestSampleGrinder g;
 582  E :    ASSERT_NO_FATAL_FAILURE(GrindSucceeds(SampleGrinder::kCompiland, true));
 583  E :  }
 584    :  
 585  E :  TEST_F(SampleGrinderTest, GrindCompilandNoImageSpecified) {
 586  E :    TestSampleGrinder g;
 587  E :    ASSERT_NO_FATAL_FAILURE(GrindSucceeds(SampleGrinder::kCompiland, false));
 588  E :  }
 589    :  
 590  E :  TEST_F(SampleGrinderTest, GrindLine) {
 591  E :    TestSampleGrinder g;
 592  E :    ASSERT_NO_FATAL_FAILURE(GrindSucceeds(SampleGrinder::kLine, true));
 593  E :  }
 594    :  
 595  E :  TEST_F(SampleGrinderTest, GrindLineNoImageSpecified) {
 596  E :    TestSampleGrinder g;
 597  E :    ASSERT_NO_FATAL_FAILURE(GrindSucceeds(SampleGrinder::kLine, false));
 598  E :  }
 599    :  
 600    :  }  // namespace grinders
 601    :  }  // namespace grinder

Coverage information generated Thu Jan 14 17:40:38 2016.