Coverage for /Syzygy/agent/memprof/function_call_logger_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
82.6%1421720.C++test

Line-by-line coverage:

   1    :  // Copyright 2014 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    :  // Function call logger unittests.
  16    :  
  17    :  #include "syzygy/agent/memprof/function_call_logger.h"
  18    :  
  19    :  #include "base/bind.h"
  20    :  #include "gmock/gmock.h"
  21    :  #include "gtest/gtest.h"
  22    :  
  23    :  namespace agent {
  24    :  namespace memprof {
  25    :  
  26    :  namespace {
  27    :  
  28    :  using trace::client::TraceFileSegment;
  29    :  
  30    :  // TODO(chrisha): Centralize this for use elsewhere.
  31    :  class TestRpcSession : public trace::client::RpcSession {
  32    :   public:
  33  E :    TestRpcSession() : closed_(false) {
  34  E :    }
  35    :  
  36  i :    virtual bool CreateSession(TraceFileSegment* segment) {
  37  i :      DCHECK_NE(static_cast<TraceFileSegment*>(nullptr), segment);
  38  i :      return AllocateBuffer(segment);
  39  i :    }
  40    :  
  41  E :    virtual bool AllocateBuffer(TraceFileSegment* segment) {
  42  E :      DCHECK_NE(static_cast<TraceFileSegment*>(nullptr), segment);
  43  E :      return AllocateBuffer(2 * 1024 * 1024, segment);
  44  E :    }
  45    :  
  46  E :    virtual bool AllocateBuffer(size_t min_size, TraceFileSegment* segment) {
  47  E :      DCHECK_NE(static_cast<TraceFileSegment*>(nullptr), segment);
  48  E :      if (closed_)
  49  i :        return false;
  50  E :      auto it = buffers_.insert(buffers_.begin(), std::vector<uint8>());
  51  E :      it->resize(min_size);
  52  E :      segment->base_ptr = it->data();
  53  E :      segment->buffer_info.buffer_offset = 0;
  54  E :      segment->buffer_info.buffer_size = min_size;
  55  E :      segment->buffer_info.shared_memory_handle = 0;
  56  E :      segment->end_ptr = segment->base_ptr + min_size;
  57    :      segment->header = reinterpret_cast<TraceFileSegmentHeader*>(
  58  E :          segment->base_ptr);
  59  E :      segment->write_ptr = reinterpret_cast<uint8*>(segment->header + 1);
  60  E :      segment->header->thread_id = ::GetCurrentThreadId();
  61  E :      segment->header->segment_length = 0;
  62  E :      return true;
  63  E :    }
  64    :  
  65  i :    virtual bool ExchangeBuffer(TraceFileSegment* segment) {
  66  i :      DCHECK_NE(static_cast<TraceFileSegment*>(nullptr), segment);
  67  i :      return AllocateBuffer(segment);
  68  i :    }
  69    :  
  70  i :    virtual bool ReturnBuffer(TraceFileSegment* segment) {
  71  i :      DCHECK_NE(static_cast<TraceFileSegment*>(nullptr), segment);
  72  i :      if (closed_)
  73  i :        return false;
  74  i :      segment->base_ptr = nullptr;
  75  i :      segment->buffer_info.buffer_offset = 0;
  76  i :      segment->buffer_info.buffer_size = 0;
  77  i :      segment->buffer_info.shared_memory_handle = 0;
  78  i :      segment->end_ptr = nullptr;
  79  i :      segment->header = nullptr;
  80  i :      segment->write_ptr = nullptr;
  81  i :      return true;
  82  i :    }
  83    :  
  84  i :    virtual bool CloseSession() {
  85  i :      if (closed_)
  86  i :        return false;
  87  i :      closed_ = true;
  88  i :      return true;
  89  i :    }
  90    :  
  91  i :    virtual void FreeSharedMemory() {
  92    :      return;
  93  i :    }
  94    :  
  95    :   private:
  96    :    // All generated buffers are kept around so that the contents of flushed
  97    :    // buffers can be inspected.
  98    :    std::list<std::vector<uint8>> buffers_;
  99    :    bool closed_;
 100    :  };
 101    :  
 102    :  class TestFunctionCallLogger : public FunctionCallLogger {
 103    :   public:
 104  E :    TestFunctionCallLogger()
 105    :        : FunctionCallLogger(&test_session_) {
 106    :      test_segment_.allocate_callback =
 107    :          base::Bind(&TestFunctionCallLogger::AllocateCallback,
 108  E :                     base::Unretained(this));
 109  E :      test_session_.AllocateBuffer(&test_segment_);
 110  E :    }
 111    :  
 112    :    using FunctionCallLogger::function_id_map_;
 113    :    using FunctionCallLogger::emitted_stack_ids_;
 114    :  
 115    :    // The session and segment that are passed to the function call logger.
 116    :    TestRpcSession test_session_;
 117    :    TraceFileSegment test_segment_;
 118    :  
 119    :    // Stores information about the allocations made to test_segment.
 120    :    struct AllocationInfo {
 121    :      int record_type;
 122    :      size_t record_size;
 123    :      void* record;
 124    :    };
 125    :    std::vector<AllocationInfo> allocation_infos;
 126    :  
 127    :    // This callback is invoked whenever test_segment is written to.
 128    :    void AllocateCallback(
 129  E :        int record_type, size_t record_size, void* record) {
 130  E :      AllocationInfo info = { record_type, record_size, record };
 131  E :      allocation_infos.push_back(info);
 132  E :    }
 133    :  };
 134    :  
 135  E :  void TestEmitDetailedFunctionCall(TestFunctionCallLogger* fcl) {
 136  E :    ASSERT_NE(static_cast<TestFunctionCallLogger*>(nullptr), fcl);
 137  E :    EMIT_DETAILED_FUNCTION_CALL(fcl, &fcl->test_segment_, fcl);
 138  E :  }
 139    :  
 140    :  }  // namespace
 141    :  
 142  E :  TEST(FunctionCallLoggerTest, TraceFunctionNameTableEntry) {
 143  E :    TestFunctionCallLogger fcl;
 144  E :    EXPECT_EQ(0u, fcl.function_id_map_.size());
 145    :  
 146  E :    std::string name("foo");
 147  E :    EXPECT_EQ(0u, fcl.GetFunctionId(&fcl.test_segment_, name));
 148  E :    EXPECT_EQ(1u, fcl.function_id_map_.size());
 149    :    EXPECT_THAT(fcl.function_id_map_,
 150  E :                testing::Contains(std::make_pair(name, 0)));
 151  E :    EXPECT_EQ(1u, fcl.allocation_infos.size());
 152    :  
 153  E :    const auto& info = fcl.allocation_infos.front();
 154    :    EXPECT_EQ(TraceFunctionNameTableEntry::kTypeId,
 155  E :              info.record_type);
 156  E :    EXPECT_TRUE(info.record != nullptr);
 157    :    TraceFunctionNameTableEntry* data =
 158    :        reinterpret_cast<TraceFunctionNameTableEntry*>(
 159  E :            info.record);
 160    :    EXPECT_LE(
 161    :        FIELD_OFFSET(TraceFunctionNameTableEntry, name) + data->name_length,
 162  E :        info.record_size);
 163  E :    EXPECT_EQ(name, data->name);
 164  E :    fcl.allocation_infos.empty();
 165    :  
 166    :    // Adding the same name again should do nothing.
 167  E :    EXPECT_EQ(0u, fcl.GetFunctionId(&fcl.test_segment_, "foo"));
 168  E :    EXPECT_EQ(1u, fcl.function_id_map_.size());
 169    :    EXPECT_THAT(fcl.function_id_map_,
 170  E :                testing::Contains(std::make_pair(std::string("foo"), 0)));
 171  E :    EXPECT_EQ(1u, fcl.allocation_infos.size());
 172  E :  }
 173    :  
 174  E :  TEST(FunctionCallLoggerTest, TraceStackTrace) {
 175  E :    TestFunctionCallLogger fcl;
 176  E :    EXPECT_EQ(0u, fcl.emitted_stack_ids_.size());
 177    :  
 178  E :    fcl.set_stack_trace_tracking(kTrackingNone);
 179  E :    EXPECT_EQ(0u, fcl.GetStackTraceId(&fcl.test_segment_));
 180  E :    EXPECT_EQ(0u, fcl.emitted_stack_ids_.size());
 181  E :    EXPECT_EQ(0u, fcl.allocation_infos.size());
 182    :  
 183  E :    fcl.set_stack_trace_tracking(kTrackingTrack);
 184  E :    EXPECT_NE(0u, fcl.GetStackTraceId(&fcl.test_segment_));
 185  E :    EXPECT_EQ(0u, fcl.emitted_stack_ids_.size());
 186  E :    EXPECT_EQ(0u, fcl.allocation_infos.size());
 187    :  
 188  E :    fcl.set_stack_trace_tracking(kTrackingEmit);
 189  E :    uint32 stack_trace_id = fcl.GetStackTraceId(&fcl.test_segment_);
 190  E :    EXPECT_NE(0u, stack_trace_id);
 191  E :    EXPECT_THAT(fcl.emitted_stack_ids_, testing::ElementsAre(stack_trace_id));
 192  E :    EXPECT_EQ(1u, fcl.allocation_infos.size());
 193  E :    const auto& info = fcl.allocation_infos[0];
 194  E :    EXPECT_EQ(TraceStackTrace::kTypeId, info.record_type);
 195  E :    EXPECT_TRUE(info.record != nullptr);
 196  E :    TraceStackTrace* data = reinterpret_cast<TraceStackTrace*>(info.record);
 197  E :    EXPECT_EQ(stack_trace_id, data->stack_trace_id);
 198  E :    EXPECT_LT(0u, data->num_frames);
 199    :    size_t expected_size = data->num_frames * sizeof(void*) +
 200  E :        FIELD_OFFSET(TraceStackTrace, frames);
 201  E :    EXPECT_LE(expected_size, info.record_size);
 202  E :  }
 203    :  
 204  E :  TEST(FunctionCallLoggerTest, TraceDetailedFunctionCall) {
 205  E :    TestFunctionCallLogger fcl;
 206  E :    fcl.set_stack_trace_tracking(kTrackingEmit);
 207  E :    EXPECT_EQ(0u, fcl.function_id_map_.size());
 208    :  
 209    :    std::string name("agent::memprof::`anonymous-namespace'::"
 210  E :                     "TestEmitDetailedFunctionCall");
 211  E :    TestEmitDetailedFunctionCall(&fcl);
 212  E :    EXPECT_EQ(1u, fcl.function_id_map_.size());
 213    :    EXPECT_THAT(fcl.function_id_map_,
 214  E :                testing::Contains(std::make_pair(name, 0)));
 215  E :    EXPECT_EQ(3u, fcl.allocation_infos.size());
 216    :  
 217    :    // Validate that the name record was appropriately written.
 218  E :    const auto& info0 = fcl.allocation_infos[0];
 219    :    EXPECT_EQ(TraceFunctionNameTableEntry::kTypeId,
 220  E :              info0.record_type);
 221  E :    EXPECT_TRUE(info0.record != nullptr);
 222    :    TraceFunctionNameTableEntry* data0 =
 223    :        reinterpret_cast<TraceFunctionNameTableEntry*>(
 224  E :            info0.record);
 225    :    EXPECT_LE(
 226    :        FIELD_OFFSET(TraceFunctionNameTableEntry, name) + data0->name_length,
 227  E :        info0.record_size);
 228  E :    EXPECT_EQ(name, data0->name);
 229    :  
 230    :    // Validate that the stack trace was written correctly.
 231  E :    const auto& info1 = fcl.allocation_infos[1];
 232  E :    EXPECT_EQ(TraceStackTrace::kTypeId, info1.record_type);
 233  E :    EXPECT_TRUE(info1.record != nullptr);
 234  E :    TraceStackTrace* data1 = reinterpret_cast<TraceStackTrace*>(info1.record);
 235  E :    EXPECT_LT(0u, data1->num_frames);
 236    :    size_t expected_size = data1->num_frames * sizeof(void*) +
 237  E :        FIELD_OFFSET(TraceStackTrace, frames);
 238  E :    EXPECT_LE(expected_size, info1.record_size);
 239    :  
 240    :    // Validate that the detailed function call record was written correctly.
 241  E :    const auto& info2 = fcl.allocation_infos[2];
 242    :    EXPECT_EQ(TraceDetailedFunctionCall::kTypeId,
 243  E :              info2.record_type);
 244  E :    EXPECT_TRUE(info2.record != nullptr);
 245    :    TraceDetailedFunctionCall* data2 =
 246  E :        reinterpret_cast<TraceDetailedFunctionCall*>(info2.record);
 247    :    EXPECT_LE(
 248    :        FIELD_OFFSET(TraceDetailedFunctionCall, argument_data) +
 249    :            data2->argument_data_size,
 250  E :        info2.record_size);
 251  E :    EXPECT_EQ(0u, data2->function_id);
 252  E :    EXPECT_EQ(data1->stack_trace_id, data2->stack_trace_id);
 253  E :    EXPECT_NE(0ull, data2->timestamp);
 254    :    // Number of arguments, size of argument, content of argument.
 255  E :    EXPECT_EQ(2 * sizeof(uint32) + sizeof(void*), data2->argument_data_size);
 256    :  
 257  E :    void* fcl_ptr = &fcl;
 258  E :    uint8 ptr[4] = {};
 259  E :    ::memcpy(ptr, &fcl_ptr, sizeof(ptr));
 260    :    const uint8 kExpectedContents[] = {
 261    :        0x01, 0x00, 0x00, 0x00,  // 1 argument...
 262    :        0x04, 0x00, 0x00, 0x00,  // ...of size 4...
 263    :        ptr[0], ptr[1], ptr[2], ptr[3],  // ...pointing to |fcl|.
 264  E :        };
 265  E :    ASSERT_EQ(arraysize(kExpectedContents), data2->argument_data_size);
 266    :    EXPECT_EQ(0u, ::memcmp(kExpectedContents, data2->argument_data,
 267  E :                           data2->argument_data_size));
 268  E :  }
 269    :  
 270  E :  TEST(FunctionCallLoggerTest, TraceDetailedFunctionCallSerializeTimestamps) {
 271  E :    TestFunctionCallLogger fcl;
 272  E :    fcl.set_stack_trace_tracking(kTrackingNone);
 273  E :    fcl.set_serialize_timestamps(true);
 274  E :    EXPECT_EQ(0u, fcl.function_id_map_.size());
 275    :  
 276    :    std::string name("agent::memprof::`anonymous-namespace'::"
 277  E :                     "TestEmitDetailedFunctionCall");
 278  E :    for (size_t i = 0; i < 3; ++i)
 279  E :      TestEmitDetailedFunctionCall(&fcl);
 280  E :    EXPECT_EQ(1u, fcl.function_id_map_.size());
 281    :    EXPECT_THAT(fcl.function_id_map_,
 282  E :                testing::Contains(std::make_pair(name, 0)));
 283    :    // 1 name, 3 calls.
 284  E :    EXPECT_EQ(4u, fcl.allocation_infos.size());
 285    :  
 286    :    // Validate that the name record was appropriately written.
 287  E :    const auto& info0 = fcl.allocation_infos[0];
 288    :    EXPECT_EQ(TraceFunctionNameTableEntry::kTypeId,
 289  E :              info0.record_type);
 290  E :    EXPECT_NE(nullptr, info0.record);
 291    :    TraceFunctionNameTableEntry* data0 =
 292    :        reinterpret_cast<TraceFunctionNameTableEntry*>(
 293  E :            info0.record);
 294    :    EXPECT_LE(
 295    :        FIELD_OFFSET(TraceFunctionNameTableEntry, name) + data0->name_length,
 296  E :        info0.record_size);
 297  E :    EXPECT_EQ(name, data0->name);
 298    :  
 299  E :    for (size_t i = 0; i < 3; ++i) {
 300    :      // Validate that the detailed function call has the appropriate timestamp.
 301  E :      const auto& info1 = fcl.allocation_infos[1 + i];
 302  E :      EXPECT_EQ(TraceDetailedFunctionCall::kTypeId, info1.record_type);
 303  E :      EXPECT_NE(nullptr, info0.record);
 304    :      TraceDetailedFunctionCall* data1 =
 305  E :          reinterpret_cast<TraceDetailedFunctionCall*>(info1.record);
 306  E :      EXPECT_EQ(static_cast<uint64>(i), data1->timestamp);
 307  E :    }
 308  E :  }
 309    :  
 310    :  }  // namespace memprof
 311    :  }  // namespace agent

Coverage information generated Thu Mar 26 16:15:41 2015.