forked from benmccann/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a WinHeap dump provider to the memory profiler.
BUG=466141 Review URL: https://codereview.chromium.org/1100173002 Cr-Commit-Position: refs/heads/master@{#326501}
- Loading branch information
1 parent
1d8f5af
commit 62215af
Showing
5 changed files
with
245 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
// Copyright 2015 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "base/trace_event/winheap_dump_provider_win.h" | ||
|
||
#include <windows.h> | ||
|
||
#include "base/trace_event/process_memory_dump.h" | ||
|
||
namespace base { | ||
namespace trace_event { | ||
|
||
namespace { | ||
|
||
const char kDumperFriendlyName[] = "winheap"; | ||
|
||
// Report a heap dump to a process memory dump. The |heap_info| structure | ||
// contains the information about this heap, and |heap_name| will be used to | ||
// represent it in the report. | ||
bool ReportHeapDump(ProcessMemoryDump* pmd, | ||
const WinHeapInfo& heap_info, | ||
const std::string& heap_name) { | ||
MemoryAllocatorDump* dump = | ||
pmd->CreateAllocatorDump(kDumperFriendlyName, heap_name); | ||
if (!dump) | ||
return false; | ||
dump->set_physical_size_in_bytes(heap_info.committed_size); | ||
dump->set_allocated_objects_count(heap_info.block_count); | ||
dump->set_allocated_objects_size_in_bytes(heap_info.allocated_size); | ||
return true; | ||
} | ||
|
||
} // namespace | ||
|
||
WinHeapDumpProvider* WinHeapDumpProvider::GetInstance() { | ||
return Singleton<WinHeapDumpProvider, | ||
LeakySingletonTraits<WinHeapDumpProvider>>::get(); | ||
} | ||
|
||
bool WinHeapDumpProvider::DumpInto(ProcessMemoryDump* pmd) { | ||
DCHECK_NE(reinterpret_cast<ProcessMemoryDump*>(nullptr), pmd); | ||
|
||
// Retrieves the number of heaps in the current process. | ||
DWORD number_of_heaps = ::GetProcessHeaps(0, NULL); | ||
WinHeapInfo all_heap_info = {0}; | ||
|
||
// Try to retrieve a handle to all the heaps owned by this process. Returns | ||
// false if the number of heaps has changed. | ||
// | ||
// This is inherently racy as is, but it's not something that we observe a lot | ||
// in Chrome, the heaps tend to be created at startup only. | ||
scoped_ptr<HANDLE[]> all_heaps(new HANDLE[number_of_heaps]); | ||
if (::GetProcessHeaps(number_of_heaps, all_heaps.get()) != number_of_heaps) | ||
return false; | ||
|
||
// Skip the pointer to the heap array to avoid accounting the memory used by | ||
// this dump provider. | ||
std::set<void*> block_to_skip; | ||
block_to_skip.insert(all_heaps.get()); | ||
|
||
// Retrieves some metrics about each heap. | ||
for (size_t i = 0; i < number_of_heaps; ++i) { | ||
WinHeapInfo heap_info = {0}; | ||
heap_info.heap_id = all_heaps[i]; | ||
GetHeapInformation(&heap_info, block_to_skip); | ||
|
||
all_heap_info.allocated_size += heap_info.allocated_size; | ||
all_heap_info.committed_size += heap_info.committed_size; | ||
all_heap_info.block_count += heap_info.block_count; | ||
} | ||
// Report the heap dump. | ||
if (!ReportHeapDump(pmd, all_heap_info, MemoryAllocatorDump::kRootHeap)) | ||
return false; | ||
|
||
return true; | ||
} | ||
|
||
const char* WinHeapDumpProvider::GetFriendlyName() const { | ||
return kDumperFriendlyName; | ||
} | ||
|
||
bool WinHeapDumpProvider::GetHeapInformation( | ||
WinHeapInfo* heap_info, | ||
const std::set<void*>& block_to_skip) { | ||
CHECK(::HeapLock(heap_info->heap_id) == TRUE); | ||
PROCESS_HEAP_ENTRY heap_entry; | ||
heap_entry.lpData = nullptr; | ||
// Walk over all the entries in this heap. | ||
while (::HeapWalk(heap_info->heap_id, &heap_entry) != FALSE) { | ||
if (block_to_skip.count(heap_entry.lpData) == 1) | ||
continue; | ||
if ((heap_entry.wFlags & PROCESS_HEAP_ENTRY_BUSY) != 0) { | ||
heap_info->allocated_size += heap_entry.cbData; | ||
heap_info->block_count++; | ||
} else if ((heap_entry.wFlags & PROCESS_HEAP_REGION) != 0) { | ||
heap_info->committed_size += heap_entry.Region.dwCommittedSize; | ||
} | ||
} | ||
CHECK(::HeapUnlock(heap_info->heap_id) == TRUE); | ||
return true; | ||
} | ||
|
||
} // namespace trace_event | ||
} // namespace base |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// Copyright 2015 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#ifndef BASE_TRACE_EVENT_WINHEAP_DUMP_PROVIDER_WIN_H_ | ||
#define BASE_TRACE_EVENT_WINHEAP_DUMP_PROVIDER_WIN_H_ | ||
|
||
#include <set> | ||
|
||
#include "base/memory/singleton.h" | ||
#include "base/trace_event/memory_dump_provider.h" | ||
|
||
namespace base { | ||
namespace trace_event { | ||
|
||
// A structure containing some information about a given heap. | ||
struct WinHeapInfo { | ||
HANDLE heap_id; | ||
size_t committed_size; | ||
size_t allocated_size; | ||
size_t block_count; | ||
}; | ||
|
||
// Dump provider which collects process-wide heap memory stats. This provider | ||
// iterates over all the heaps of the current process to gather some metrics | ||
// about them. | ||
class BASE_EXPORT WinHeapDumpProvider : public MemoryDumpProvider { | ||
public: | ||
static WinHeapDumpProvider* GetInstance(); | ||
|
||
// MemoryDumpProvider implementation. | ||
bool DumpInto(ProcessMemoryDump* pmd) override; | ||
const char* GetFriendlyName() const override; | ||
|
||
private: | ||
friend class WinHeapDumpProviderTest; | ||
friend struct DefaultSingletonTraits<WinHeapDumpProvider>; | ||
|
||
// Retrieves the information about given heap. The |heap_info| should contain | ||
// a valid handle to an existing heap. The blocks contained in the | ||
// |block_to_skip| set will be ignored. | ||
bool GetHeapInformation(WinHeapInfo* heap_info, | ||
const std::set<void*>& block_to_skip); | ||
|
||
WinHeapDumpProvider() {} | ||
~WinHeapDumpProvider() override {} | ||
|
||
DISALLOW_COPY_AND_ASSIGN(WinHeapDumpProvider); | ||
}; | ||
|
||
} // namespace trace_event | ||
} // namespace base | ||
|
||
#endif // BASE_TRACE_EVENT_WINHEAP_DUMP_PROVIDER_WIN_H_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
// Copyright 2015 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "base/trace_event/winheap_dump_provider_win.h" | ||
|
||
#include <windows.h> | ||
|
||
#include "base/trace_event/memory_dump_session_state.h" | ||
#include "base/trace_event/process_memory_dump.h" | ||
#include "testing/gtest/include/gtest/gtest.h" | ||
|
||
namespace base { | ||
namespace trace_event { | ||
|
||
class WinHeapDumpProviderTest : public testing::Test { | ||
public: | ||
bool GetHeapInformation(WinHeapDumpProvider* provider, | ||
WinHeapInfo* heap_info, | ||
const std::set<void*>& block_to_skip) { | ||
return provider->GetHeapInformation(heap_info, block_to_skip); | ||
} | ||
}; | ||
|
||
TEST_F(WinHeapDumpProviderTest, DumpInto) { | ||
ProcessMemoryDump pmd(make_scoped_refptr(new MemoryDumpSessionState())); | ||
|
||
WinHeapDumpProvider* winheap_dump_provider = | ||
WinHeapDumpProvider::GetInstance(); | ||
ASSERT_NE(reinterpret_cast<WinHeapDumpProvider*>(nullptr), | ||
winheap_dump_provider); | ||
|
||
ASSERT_TRUE(winheap_dump_provider->DumpInto(&pmd)); | ||
} | ||
|
||
TEST_F(WinHeapDumpProviderTest, GetHeapInformation) { | ||
ProcessMemoryDump pmd(make_scoped_refptr(new MemoryDumpSessionState())); | ||
|
||
WinHeapDumpProvider* winheap_dump_provider = | ||
WinHeapDumpProvider::GetInstance(); | ||
ASSERT_NE(reinterpret_cast<WinHeapDumpProvider*>(nullptr), | ||
winheap_dump_provider); | ||
|
||
HANDLE heap = ::HeapCreate(NULL, 0, 0); | ||
ASSERT_NE(nullptr, heap); | ||
|
||
const size_t kAllocSize = 42; | ||
void* alloc = ::HeapAlloc(heap, 0, kAllocSize); | ||
ASSERT_NE(nullptr, alloc); | ||
|
||
WinHeapInfo heap_info = {0}; | ||
heap_info.heap_id = heap; | ||
std::set<void*> block_to_skip; | ||
|
||
// Put the allocation into the skip list and make sure that the provider | ||
// ignores it. | ||
block_to_skip.insert(alloc); | ||
ASSERT_TRUE( | ||
GetHeapInformation(winheap_dump_provider, &heap_info, block_to_skip)); | ||
EXPECT_EQ(0U, heap_info.block_count); | ||
EXPECT_EQ(0U, heap_info.allocated_size); | ||
// We can't check the committed size here, as it can depend on the version of | ||
// kernel32.dll. | ||
|
||
// Remove the allocation from the skip list and check if it's analysed | ||
// properlyly. | ||
block_to_skip.erase(alloc); | ||
ASSERT_TRUE( | ||
GetHeapInformation(winheap_dump_provider, &heap_info, block_to_skip)); | ||
EXPECT_EQ(1, heap_info.block_count); | ||
EXPECT_EQ(kAllocSize, heap_info.allocated_size); | ||
EXPECT_LT(kAllocSize, heap_info.committed_size); | ||
|
||
EXPECT_TRUE(::HeapFree(heap, 0, alloc)); | ||
EXPECT_EQ(TRUE, ::HeapDestroy(heap)); | ||
} | ||
|
||
} // namespace trace_event | ||
} // namespace base |