Commit 237a1485 authored by jamesr@chromium.org's avatar jamesr@chromium.org

Route calls to tcmalloc MallocExtension through allocator agnostic interface

Our various libraries should not be picking or depending on a particular
allocator choice - that should be an application level choice. This creates
a generic AllocatorExtension interface that can optionally be backed by
entry points to a particular allocator's MallocExtension interface if the
application chooses to.

BUG=125003
TEST=compiles, chrome://tcmalloc works


Review URL: http://codereview.chromium.org/10239012

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@134434 0039d316-1c4b-4281-b951-d872f2087c98
parent 6486d9c1
...@@ -427,7 +427,22 @@ ...@@ -427,7 +427,22 @@
}], }],
], ],
}, },
{
# This library is linked in to libbase and allocator_unittests.
# It can't depend on either and nothing else should depend on it -
# all other code should use the interfaced provided by libbase.
'target_name': 'allocator_extension_thunks',
'type': 'static_library',
'sources': [
'allocator_extension_thunks.cc',
'allocator_extension_thunks.h',
], ],
'toolsets': ['host', 'target'],
'include_dirs': [
'../../'
],
},
],
'conditions': [ 'conditions': [
['OS=="win"', { ['OS=="win"', {
'targets': [ 'targets': [
...@@ -456,6 +471,7 @@ ...@@ -456,6 +471,7 @@
'type': 'executable', 'type': 'executable',
'dependencies': [ 'dependencies': [
'allocator', 'allocator',
'allocator_extension_thunks',
'../../testing/gtest.gyp:gtest', '../../testing/gtest.gyp:gtest',
], ],
'include_dirs': [ 'include_dirs': [
...@@ -470,6 +486,23 @@ ...@@ -470,6 +486,23 @@
'../profiler/alternate_timer.h', '../profiler/alternate_timer.h',
], ],
}, },
{
'target_name': 'allocator_extension_thunks_win64',
'type': 'static_library',
'sources': [
'allocator_extension_thunks.cc',
'allocator_extension_thunks.h',
],
'toolsets': ['host', 'target'],
'include_dirs': [
'../../'
],
'configurations': {
'Common_Base': {
'msvs_target_platform': 'x64',
},
},
},
], ],
}], }],
], ],
......
// Copyright (c) 2012 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/allocator/allocator_extension.h"
#include "base/logging.h"
namespace base {
namespace allocator {
void GetStats(char* buffer, int buffer_length) {
DCHECK_GT(buffer_length, 0);
if (thunks::GetStatsFunction* get_stats_function =
base::allocator::thunks::GetGetStatsFunction())
get_stats_function(buffer, buffer_length);
else
buffer[0] = '\0';
}
void ReleaseFreeMemory() {
if (thunks::ReleaseFreeMemoryFunction* release_free_memory_function =
base::allocator::thunks::GetReleaseFreeMemoryFunction())
release_free_memory_function();
}
void SetGetStatsFunction(thunks::GetStatsFunction* get_stats_function) {
DCHECK_EQ(base::allocator::thunks::GetGetStatsFunction(),
reinterpret_cast<thunks::GetStatsFunction*>(NULL));
base::allocator::thunks::SetGetStatsFunction(get_stats_function);
}
void SetReleaseFreeMemoryFunction(
thunks::ReleaseFreeMemoryFunction* release_free_memory_function) {
DCHECK_EQ(base::allocator::thunks::GetReleaseFreeMemoryFunction(),
reinterpret_cast<thunks::ReleaseFreeMemoryFunction*>(NULL));
base::allocator::thunks::SetReleaseFreeMemoryFunction(
release_free_memory_function);
}
} // namespace allocator
} // namespace base
// Copyright (c) 2012 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_ALLOCATOR_ALLOCATOR_EXTENSION_H
#define BASE_ALLOCATOR_ALLOCATOR_EXTENSION_H
#pragma once
#include "base/allocator/allocator_extension_thunks.h"
#include "base/base_export.h"
#include "build/build_config.h"
namespace base {
namespace allocator {
// Request that the allocator print a human-readable description of the current
// state of the allocator into a null-terminated string in the memory segment
// buffer[0,buffer_length-1].
//
// |buffer| must point to a valid piece of memory
// |buffer_length| must be > 0.
BASE_EXPORT void GetStats(char* buffer, int buffer_length);
// Request that the allocator release any free memory it knows about to the
// system.
BASE_EXPORT void ReleaseFreeMemory();
// These settings allow specifying a callback used to implement the allocator
// extension functions. These are optional, but if set they must only be set
// once. These will typically called in an allocator-specific initialization
// routine.
//
// No threading promises are made. The caller is responsible for making sure
// these pointers are set before any other threads attempt to call the above
// functions.
BASE_EXPORT void SetGetStatsFunction(
thunks::GetStatsFunction* get_stats_function);
BASE_EXPORT void SetReleaseFreeMemoryFunction(
thunks::ReleaseFreeMemoryFunction* release_free_memory_function);
} // namespace allocator
} // namespace base
#endif
// Copyright (c) 2012 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/allocator/allocator_extension_thunks.h"
#include <cstddef> // for NULL
namespace base {
namespace allocator {
namespace thunks {
// This slightly odd translation unit exists because of the peculularity of how
// allocator_unittests works on windows. That target has to perform
// tcmalloc-specific initialization on windows, but it cannot depend on base
// otherwise. This target sits in the middle - both libbase and
// allocator_unittests can depend on it.
// This file can't depend on anything else in base, including logging.
static GetStatsFunction* g_get_stats_function = NULL;
static ReleaseFreeMemoryFunction* g_release_free_memory_function = NULL;
void SetGetStatsFunction(GetStatsFunction* get_stats_function) {
g_get_stats_function = get_stats_function;
}
GetStatsFunction* GetGetStatsFunction() {
return g_get_stats_function;
}
void SetReleaseFreeMemoryFunction(
ReleaseFreeMemoryFunction* release_free_memory_function) {
g_release_free_memory_function = release_free_memory_function;
}
ReleaseFreeMemoryFunction* GetReleaseFreeMemoryFunction() {
return g_release_free_memory_function;
}
} // namespace thunks
} // namespace allocator
} // namespace base
// Copyright (c) 2012 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_ALLOCATOR_ALLOCATOR_THUNKS_EXTENSION_H
#define BASE_ALLOCATOR_ALLOCATOR_THUNKS_EXTENSION_H
#pragma once
namespace base {
namespace allocator {
namespace thunks {
// WARNING: You probably don't want to use this file unless you are routing a
// new allocator extension from a specific allocator implementation to base.
// See allocator_extension.h to see the interface that base exports.
typedef void GetStatsFunction(char*, int);
void SetGetStatsFunction(GetStatsFunction* get_stats_function);
GetStatsFunction* GetGetStatsFunction();
typedef void ReleaseFreeMemoryFunction();
void SetReleaseFreeMemoryFunction(
ReleaseFreeMemoryFunction* release_free_memory_function);
ReleaseFreeMemoryFunction* GetReleaseFreeMemoryFunction();
} // namespace thunks
} // namespace allocator
} // namespace base
#endif
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "base/allocator/allocator_shim.h" #include "base/allocator/allocator_shim.h"
#include <config.h> #include <config.h>
#include "base/allocator/allocator_extension_thunks.h"
#include "base/profiler/alternate_timer.h" #include "base/profiler/alternate_timer.h"
#include "base/sysinfo.h" #include "base/sysinfo.h"
...@@ -229,6 +230,14 @@ extern "C" intptr_t _get_heap_handle() { ...@@ -229,6 +230,14 @@ extern "C" intptr_t _get_heap_handle() {
return 0; return 0;
} }
static void get_stats_thunk(char* buffer, int buffer_length) {
MallocExtension::instance()->GetStats(buffer, buffer_length);
}
static void release_free_memory_thunk() {
MallocExtension::instance()->ReleaseFreeMemory();
}
// The CRT heap initialization stub. // The CRT heap initialization stub.
extern "C" int _heap_init() { extern "C" int _heap_init() {
#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
...@@ -274,6 +283,10 @@ extern "C" int _heap_init() { ...@@ -274,6 +283,10 @@ extern "C" int _heap_init() {
tracked_objects::TIME_SOURCE_TYPE_TCMALLOC); tracked_objects::TIME_SOURCE_TYPE_TCMALLOC);
} }
base::allocator::thunks::SetGetStatsFunction(get_stats_thunk);
base::allocator::thunks::SetReleaseFreeMemoryFunction(
release_free_memory_thunk);
return 1; return 1;
} }
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
'third_party/nspr/prtime.h', 'third_party/nspr/prtime.h',
'third_party/nspr/prcpucfg_linux.h', 'third_party/nspr/prcpucfg_linux.h',
'third_party/xdg_mime/xdgmime.h', 'third_party/xdg_mime/xdgmime.h',
'allocator/allocator_extension.cc',
'allocator/allocator_extension.h',
'android/base_jni_registrar.cc', 'android/base_jni_registrar.cc',
'android/base_jni_registrar.h', 'android/base_jni_registrar.h',
'android/build_info.cc', 'android/build_info.cc',
...@@ -589,6 +591,7 @@ ...@@ -589,6 +591,7 @@
}, },
'dependencies': [ 'dependencies': [
'base_static', 'base_static',
'allocator/allocator.gyp:allocator_extension_thunks',
'../testing/gtest.gyp:gtest_prod', '../testing/gtest.gyp:gtest_prod',
'../third_party/modp_b64/modp_b64.gyp:modp_b64', '../third_party/modp_b64/modp_b64.gyp:modp_b64',
'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', 'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
...@@ -808,6 +811,7 @@ ...@@ -808,6 +811,7 @@
}, },
'dependencies': [ 'dependencies': [
'base_static_win64', 'base_static_win64',
'allocator/allocator.gyp:allocator_extension_thunks_win64',
'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations_win64', 'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations_win64',
], ],
# TODO(gregoryd): direct_dependent_settings should be shared with the # TODO(gregoryd): direct_dependent_settings should be shared with the
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <set> #include <set>
#include "base/allocator/allocator_extension.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/threading/thread.h" #include "base/threading/thread.h"
#include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process.h"
...@@ -22,7 +23,6 @@ ...@@ -22,7 +23,6 @@
#include "net/proxy/proxy_service.h" #include "net/proxy/proxy_service.h"
#include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h" #include "net/url_request/url_request_context_getter.h"
#include "third_party/tcmalloc/chromium/src/gperftools/malloc_extension.h"
using content::BrowserContext; using content::BrowserContext;
using content::BrowserThread; using content::BrowserThread;
...@@ -131,14 +131,12 @@ void MemoryPurger::PurgeBrowser() { ...@@ -131,14 +131,12 @@ void MemoryPurger::PurgeBrowser() {
// * Purge AppCache memory. Not yet implemented sufficiently. // * Purge AppCache memory. Not yet implemented sufficiently.
// * Browser-side DatabaseTracker. Not implemented sufficiently. // * Browser-side DatabaseTracker. Not implemented sufficiently.
#if !defined(OS_MACOSX) && defined(USE_TCMALLOC) // Tell our allocator to release any free pages it's still holding.
// Tell tcmalloc to release any free pages it's still holding.
// //
// TODO(pkasting): A lot of the above calls kick off actions on other threads. // TODO(pkasting): A lot of the above calls kick off actions on other threads.
// Maybe we should find a way to avoid calling this until those actions // Maybe we should find a way to avoid calling this until those actions
// complete? // complete?
MallocExtension::instance()->ReleaseFreeMemory(); base::allocator::ReleaseFreeMemory();
#endif
} }
// static // static
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "chrome/renderer/chrome_render_process_observer.h" #include "chrome/renderer/chrome_render_process_observer.h"
#include "base/allocator/allocator_extension.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/file_util.h" #include "base/file_util.h"
...@@ -35,7 +36,6 @@ ...@@ -35,7 +36,6 @@
#include "net/base/net_module.h" #include "net/base/net_module.h"
#include "third_party/sqlite/sqlite3.h" #include "third_party/sqlite/sqlite3.h"
#include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h" #include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h"
#include "third_party/tcmalloc/chromium/src/gperftools/malloc_extension.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebCache.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebCache.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebCrossOriginPreflightResultCache.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebCrossOriginPreflightResultCache.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
...@@ -329,10 +329,8 @@ void ChromeRenderProcessObserver::OnPurgeMemory() { ...@@ -329,10 +329,8 @@ void ChromeRenderProcessObserver::OnPurgeMemory() {
v8::V8::LowMemoryNotification(); v8::V8::LowMemoryNotification();
#if !defined(OS_MACOSX) && defined(USE_TCMALLOC) // Tell our allocator to release any free pages it's still holding.
// Tell tcmalloc to release any free pages it's still holding. base::allocator::ReleaseFreeMemory();
MallocExtension::instance()->ReleaseFreeMemory();
#endif
if (client_) if (client_)
client_->OnPurgeMemory(); client_->OnPurgeMemory();
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "content/public/app/content_main_runner.h" #include "content/public/app/content_main_runner.h"
#include "base/allocator/allocator_extension.h"
#include "base/at_exit.h" #include "base/at_exit.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/debug/debugger.h" #include "base/debug/debugger.h"
...@@ -37,6 +38,10 @@ ...@@ -37,6 +38,10 @@
#include "ui/base/win/dpi.h" #include "ui/base/win/dpi.h"
#include "webkit/glue/webkit_glue.h" #include "webkit/glue/webkit_glue.h"
#if defined(USE_TCMALLOC)
#include "third_party/tcmalloc/chromium/src/gperftools/malloc_extension.h"
#endif
#if defined(OS_WIN) #if defined(OS_WIN)
#include <atlbase.h> #include <atlbase.h>
#include <atlapp.h> #include <atlapp.h>
...@@ -314,6 +319,17 @@ class ContentMainRunnerImpl : public content::ContentMainRunner { ...@@ -314,6 +319,17 @@ class ContentMainRunnerImpl : public content::ContentMainRunner {
Shutdown(); Shutdown();
} }
#if defined(USE_TCMALLOC)
static void GetStatsThunk(char* buffer, int buffer_length) {
MallocExtension::instance()->GetStats(buffer, buffer_length);
}
static void ReleaseFreeMemoryThunk() {
MallocExtension::instance()->ReleaseFreeMemory();
}
#endif
#if defined(OS_WIN) #if defined(OS_WIN)
virtual int Initialize(HINSTANCE instance, virtual int Initialize(HINSTANCE instance,
sandbox::SandboxInterfaceInfo* sandbox_info, sandbox::SandboxInterfaceInfo* sandbox_info,
...@@ -343,6 +359,10 @@ class ContentMainRunnerImpl : public content::ContentMainRunner { ...@@ -343,6 +359,10 @@ class ContentMainRunnerImpl : public content::ContentMainRunner {
#if !defined(OS_MACOSX) && defined(USE_TCMALLOC) #if !defined(OS_MACOSX) && defined(USE_TCMALLOC)
// For tcmalloc, we need to tell it to behave like new. // For tcmalloc, we need to tell it to behave like new.
tc_set_new_mode(1); tc_set_new_mode(1);
// On windows, we've already set these thunks up in _heap_init()
base::allocator::SetGetStatsFunction(GetStatsThunk);
base::allocator::SetReleaseFreeMemoryFunction(ReleaseFreeMemoryThunk);
#endif #endif
#if !defined(OS_ANDROID) #if !defined(OS_ANDROID)
......
...@@ -4,16 +4,13 @@ ...@@ -4,16 +4,13 @@
#include "content/browser/tcmalloc_internals_request_job.h" #include "content/browser/tcmalloc_internals_request_job.h"
#include "base/allocator/allocator_extension.h"
#include "content/common/child_process_messages.h" #include "content/common/child_process_messages.h"
#include "content/public/browser/browser_child_process_host_iterator.h" #include "content/public/browser/browser_child_process_host_iterator.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h" #include "content/public/browser/render_process_host.h"
#include "content/public/common/process_type.h" #include "content/public/common/process_type.h"
#if defined(USE_TCMALLOC)
#include "third_party/tcmalloc/chromium/src/gperftools/malloc_extension.h"
#endif
namespace content { namespace content {
// static // static
...@@ -88,7 +85,7 @@ void AboutTcmalloc(std::string* data) { ...@@ -88,7 +85,7 @@ void AboutTcmalloc(std::string* data) {
// Populate the collector with stats from the local browser process // Populate the collector with stats from the local browser process
// and send off requests to all the renderer processes. // and send off requests to all the renderer processes.
char buffer[1024 * 32]; char buffer[1024 * 32];
MallocExtension::instance()->GetStats(buffer, sizeof(buffer)); base::allocator::GetStats(buffer, sizeof(buffer));
std::string browser("Browser"); std::string browser("Browser");
AboutTcmallocOutputs::GetInstance()->SetOutput(browser, buffer); AboutTcmallocOutputs::GetInstance()->SetOutput(browser, buffer);
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "content/common/child_thread.h" #include "content/common/child_thread.h"
#include "base/allocator/allocator_extension.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/message_loop.h" #include "base/message_loop.h"
#include "base/process.h" #include "base/process.h"
...@@ -27,10 +28,6 @@ ...@@ -27,10 +28,6 @@
#include "content/common/handle_enumerator_win.h" #include "content/common/handle_enumerator_win.h"
#endif #endif
#if defined(USE_TCMALLOC)
#include "third_party/tcmalloc/chromium/src/gperftools/malloc_extension.h"
#endif
using tracked_objects::ThreadData; using tracked_objects::ThreadData;
ChildThread::ChildThread() { ChildThread::ChildThread() {
...@@ -257,7 +254,7 @@ void ChildThread::OnDumpHandles() { ...@@ -257,7 +254,7 @@ void ChildThread::OnDumpHandles() {
void ChildThread::OnGetTcmallocStats() { void ChildThread::OnGetTcmallocStats() {
std::string result; std::string result;
char buffer[1024 * 32]; char buffer[1024 * 32];
MallocExtension::instance()->GetStats(buffer, sizeof(buffer)); base::allocator::GetStats(buffer, sizeof(buffer));
result.append(buffer); result.append(buffer);
Send(new ChildProcessHostMsg_TcmallocStats(result)); Send(new ChildProcessHostMsg_TcmallocStats(result));
} }
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <map> #include <map>
#include <vector> #include <vector>
#include "base/allocator/allocator_extension.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/debug/trace_event.h" #include "base/debug/trace_event.h"
#include "base/lazy_instance.h" #include "base/lazy_instance.h"
...@@ -64,7 +65,6 @@ ...@@ -64,7 +65,6 @@
#include "media/base/media.h" #include "media/base/media.h"
#include "net/base/net_errors.h" #include "net/base/net_errors.h"
#include "net/base/net_util.h" #include "net/base/net_util.h"
#include "third_party/tcmalloc/chromium/src/gperftools/malloc_extension.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebColorName.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebColorName.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebCompositor.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebCompositor.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDatabase.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebDatabase.h"
...@@ -633,9 +633,8 @@ void RenderThreadImpl::IdleHandler() { ...@@ -633,9 +633,8 @@ void RenderThreadImpl::IdleHandler() {
IdleHandlerInForegroundTab(); IdleHandlerInForegroundTab();
return; return;
} }
#if !defined(OS_MACOSX) && defined(USE_TCMALLOC)
MallocExtension::instance()->ReleaseFreeMemory(); base::allocator::ReleaseFreeMemory();
#endif
v8::V8::IdleNotification(); v8::V8::IdleNotification();
...@@ -673,9 +672,7 @@ void RenderThreadImpl::IdleHandlerInForegroundTab() { ...@@ -673,9 +672,7 @@ void RenderThreadImpl::IdleHandlerInForegroundTab() {
// idle pause. We set it proportional to the idle timer delay. // idle pause. We set it proportional to the idle timer delay.
int idle_hint = static_cast<int>(new_delay_ms / 10); int idle_hint = static_cast<int>(new_delay_ms / 10);
if (cpu_usage < kIdleCPUUsageThresholdInPercents) { if (cpu_usage < kIdleCPUUsageThresholdInPercents) {
#if !defined(OS_MACOSX) && defined(USE_TCMALLOC) base::allocator::ReleaseFreeMemory();
MallocExtension::instance()->ReleaseFreeMemory();
#endif
if (v8::V8::IdleNotification(idle_hint)) { if (v8::V8::IdleNotification(idle_hint)) {
// V8 finished collecting garbage. // V8 finished collecting garbage.
new_delay_ms = kLongIdleHandlerDelayMs; new_delay_ms = kLongIdleHandlerDelayMs;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment