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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
100.0%1101100.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/grinder/grinders/profile_grinder.h"
  16    :  
  17    :  #include "base/win/scoped_com_initializer.h"
  18    :  #include "gtest/gtest.h"
  19    :  #include "syzygy/core/unittest_util.h"
  20    :  #include "syzygy/pe/unittest_util.h"
  21    :  
  22    :  namespace grinder {
  23    :  namespace grinders {
  24    :  
  25    :  namespace {
  26    :  
  27    :  const wchar_t kProfileTraceFile[] = L"profile_traces/trace-1.bin";
  28    :  
  29    :  class TestProfileGrinder : public ProfileGrinder {
  30    :   public:
  31    :    // Expose for testing.
  32    :    using ProfileGrinder::CodeLocation;
  33    :    using ProfileGrinder::FunctionLocation;
  34    :    using ProfileGrinder::PartData;
  35    :    using ProfileGrinder::FindOrCreatePart;
  36    :  
  37    :    typedef ProfileGrinder::InvocationNodeMap InvocationNodeMap;
  38    :  
  39    :    using ProfileGrinder::parser_;
  40    :    using ProfileGrinder::parts_;
  41    :  };
  42    :  
  43    :  class ProfileGrinderTest : public testing::PELibUnitTest {
  44    :   public:
  45    :    typedef testing::PELibUnitTest Super;
  46    :  
  47  E :    ProfileGrinderTest() : cmd_line_(base::FilePath(L"profile_grinder.exe")) {
  48  E :    }
  49    :  
  50  E :    virtual void SetUp() override {
  51  E :      Super::Test::SetUp();
  52  E :      cmd_line_.AppendSwitchASCII("mode", "profile");
  53  E :    }
  54    :  
  55  E :    void InitParser(trace::parser::ParseEventHandlerImpl* handler) {
  56  E :      ASSERT_TRUE(handler != NULL);
  57    :  
  58  E :      ASSERT_TRUE(parser_.Init(handler));
  59    :  
  60    :      base::FilePath trace_file =
  61  E :          testing::GetExeTestDataRelativePath(kProfileTraceFile);
  62    :  
  63  E :      ASSERT_TRUE(parser_.OpenTraceFile(trace_file));
  64  E :    }
  65    :  
  66  E :    void GrindAndOutputSucceeds() {
  67  E :      TestProfileGrinder grinder;
  68  E :      grinder.ParseCommandLine(&cmd_line_);
  69    :  
  70  E :      ASSERT_NO_FATAL_FAILURE(InitParser(&grinder));
  71  E :      grinder.SetParser(&parser_);
  72  E :      ASSERT_TRUE(parser_.Consume());
  73    :  
  74  E :      EXPECT_TRUE(grinder.Grind());
  75    :  
  76  E :      testing::ScopedTempFile output_path;
  77  E :      base::ScopedFILE output_file(base::OpenFile(output_path.path(), "wb"));
  78  E :      ASSERT_TRUE(output_file.get() != NULL);
  79    :  
  80  E :      EXPECT_TRUE(grinder.OutputData(output_file.get()));
  81  E :      output_file.reset();
  82    :  
  83  E :      int64 cache_grind_file_size = 0;
  84  E :      ASSERT_TRUE(base::GetFileSize(output_path.path(),
  85    :                                    &cache_grind_file_size));
  86  E :      EXPECT_LT(0u, cache_grind_file_size);
  87  E :    }
  88    :  
  89  E :    void IssueSetupEvents(TestProfileGrinder* grinder) {
  90    :      grinder->OnThreadName(base::Time::Now(),
  91    :                            ::GetCurrentProcessId(),
  92    :                            ::GetCurrentThreadId(),
  93  E :                            "TestThread");
  94    :  
  95    :      grinder->OnDynamicSymbol(::GetCurrentProcessId(),
  96    :                               kFunctionSymbolId,
  97  E :                               "Function");
  98    :  
  99    :      grinder->OnDynamicSymbol(::GetCurrentProcessId(),
 100    :                               kCallerSymbolId,
 101  E :                               "Caller");
 102  E :    }
 103    :  
 104    :    static const uint32 kFunctionSymbolId = 0x10;
 105    :    static const uint32 kCallerSymbolId = 0x33;
 106    :  
 107  E :    void IssueSymbolInvocationEvent(TestProfileGrinder* grinder) {
 108  E :      TraceBatchInvocationInfo batch = {};
 109  E :      batch.invocations[0].function_symbol_id = kFunctionSymbolId;
 110  E :      batch.invocations[0].caller_symbol_id = kCallerSymbolId;
 111  E :      batch.invocations[0].caller_offset = 0x30;
 112    :  
 113  E :      batch.invocations[0].num_calls = 1000;
 114  E :      batch.invocations[0].flags = kFunctionIsSymbol | kCallerIsSymbol;
 115  E :      batch.invocations[0].cycles_min = 10;
 116  E :      batch.invocations[0].cycles_max = 1000;
 117  E :      batch.invocations[0].cycles_sum = 1000 * 100;
 118    :  
 119    :      grinder->OnInvocationBatch(base::Time::Now(),
 120    :                                 ::GetCurrentProcessId(),
 121    :                                 ::GetCurrentThreadId(),
 122    :                                 1,
 123  E :                                 &batch);
 124  E :    }
 125    :  
 126    :    // Ensures that COM is initialized for tests in this fixture.
 127    :    base::win::ScopedCOMInitializer com_initializer_;
 128    :  
 129    :    base::CommandLine cmd_line_;
 130    :    trace::parser::Parser parser_;
 131    :  };
 132    :  
 133    :  }  // namespace
 134    :  
 135  E :  TEST_F(ProfileGrinderTest, CodeLocation) {
 136    :    typedef TestProfileGrinder::CodeLocation CodeLocation;
 137    :  
 138  E :    CodeLocation loc1;
 139  E :    EXPECT_FALSE(loc1.is_symbol());
 140  E :    EXPECT_EQ(NULL, loc1.module());
 141  E :    EXPECT_EQ(0, loc1.rva());
 142    :  
 143  E :    EXPECT_TRUE(loc1 == CodeLocation());
 144    :  
 145    :    // Change location to a symbol.
 146  E :    const uint32 kSymbolId = 0x1345;
 147  E :    const size_t kSymbolOffset = 0x13;
 148  E :    loc1.Set(::GetCurrentProcessId(), kSymbolId, kSymbolOffset);
 149  E :    EXPECT_TRUE(loc1.is_symbol());
 150  E :    EXPECT_EQ(::GetCurrentProcessId(), loc1.process_id());
 151  E :    EXPECT_EQ(kSymbolId, loc1.symbol_id());
 152  E :    EXPECT_EQ(kSymbolOffset, loc1.symbol_offset());
 153    :  
 154  E :    EXPECT_FALSE(loc1 == CodeLocation());
 155    :  
 156    :    // Test copy construction.
 157  E :    EXPECT_TRUE(loc1 == CodeLocation(loc1));
 158    :  
 159  E :    CodeLocation loc2;
 160    :    // loc2 differs only in offset from loc1.
 161  E :    loc2.Set(::GetCurrentProcessId(), kSymbolId, 0);
 162  E :    EXPECT_TRUE(loc2 != loc1);
 163  E :    EXPECT_TRUE(loc2 < loc1);
 164    :  
 165  E :    const pe::ModuleInformation kModuleInfo;
 166  E :    const RVA kRva = 0x10945;
 167    :    // Change them both to module/rva, and test for equality.
 168  E :    loc1.Set(&kModuleInfo, kRva);
 169  E :    loc2.Set(&kModuleInfo, kRva);
 170    :  
 171  E :    EXPECT_TRUE(loc1 == loc2);
 172  E :  }
 173    :  
 174  E :  TEST_F(ProfileGrinderTest, GrindSymbolTestData) {
 175    :    // Issue a symbol invocation event against a test grinder.
 176  E :    TestProfileGrinder grinder;
 177  E :    IssueSetupEvents(&grinder);
 178  E :    IssueSymbolInvocationEvent(&grinder);
 179    :  
 180    :    // Grind the data.
 181  E :    ASSERT_TRUE(grinder.Grind());
 182    :  
 183    :    // Then retrieve and validate the data.
 184  E :    ASSERT_EQ(1, grinder.parts_.size());
 185    :    TestProfileGrinder::PartData* part =
 186    :        grinder.FindOrCreatePart(::GetCurrentProcessId(),
 187  E :                                 ::GetCurrentThreadId());
 188    :  
 189  E :    ASSERT_TRUE(part != NULL);
 190  E :    ASSERT_EQ("TestThread", part->thread_name_);
 191    :  
 192    :    // We get one node for the (unknown) caller, and one for the function called.
 193  E :    ASSERT_EQ(2, part->nodes_.size());
 194    :  
 195  E :    TestProfileGrinder::InvocationNodeMap::iterator it = part->nodes_.begin();
 196    :  
 197  E :    EXPECT_TRUE(it->first.is_symbol());
 198  E :    EXPECT_EQ(::GetCurrentProcessId(), it->first.process_id());
 199  E :    EXPECT_EQ(kFunctionSymbolId, it->first.symbol_id());
 200    :  
 201  E :    ++it;
 202  E :    ASSERT_TRUE(it != part->nodes_.end());
 203    :  
 204  E :    EXPECT_TRUE(it->first.is_symbol());
 205  E :    EXPECT_EQ(::GetCurrentProcessId(), it->first.process_id());
 206  E :    EXPECT_EQ(kCallerSymbolId, it->first.symbol_id());
 207  E :  }
 208    :  
 209  E :  TEST_F(ProfileGrinderTest, ParseEmptyCommandLineSucceeds) {
 210  E :    TestProfileGrinder grinder;
 211  E :    EXPECT_TRUE(grinder.ParseCommandLine(&cmd_line_));
 212  E :    EXPECT_FALSE(grinder.thread_parts());
 213  E :  }
 214    :  
 215  E :  TEST_F(ProfileGrinderTest, ParseThreadPartsSwitchOnCommandLine) {
 216  E :    TestProfileGrinder grinder;
 217  E :    cmd_line_.AppendSwitch("thread-parts");
 218  E :    EXPECT_TRUE(grinder.ParseCommandLine(&cmd_line_));
 219  E :  }
 220    :  
 221  E :  TEST_F(ProfileGrinderTest, SetParserSucceeds) {
 222  E :    TestProfileGrinder grinder;
 223  E :    grinder.ParseCommandLine(&cmd_line_);
 224    :  
 225  E :    ASSERT_NO_FATAL_FAILURE(InitParser(&grinder));
 226    :  
 227  E :    grinder.SetParser(&parser_);
 228  E :    EXPECT_EQ(&parser_, grinder.parser_);
 229  E :  }
 230    :  
 231  E :  TEST_F(ProfileGrinderTest, GrindAndOutputCacheGrindDataSucceeds) {
 232  E :    ASSERT_NO_FATAL_FAILURE(GrindAndOutputSucceeds());
 233    :    // TODO(etienneb): Validate the output is a valid CacheGrind file.
 234  E :  }
 235    :  
 236    :  }  // namespace grinders
 237    :  }  // namespace grinder

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