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 @@
}],
],
},
{
# 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': [
['OS=="win"', {
'targets': [
......@@ -456,6 +471,7 @@
'type': 'executable',
'dependencies': [
'allocator',
'allocator_extension_thunks',
'../../testing/gtest.gyp:gtest',
],
'include_dirs': [
......@@ -470,6 +486,23 @@
'../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 @@
#include "base/allocator/allocator_shim.h"
#include <config.h>
#include "base/allocator/allocator_extension_thunks.h"
#include "base/profiler/alternate_timer.h"
#include "base/sysinfo.h"
......@@ -229,6 +230,14 @@ extern "C" intptr_t _get_heap_handle() {
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.
extern "C" int _heap_init() {
#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
......@@ -274,6 +283,10 @@ extern "C" int _heap_init() {
tracked_objects::TIME_SOURCE_TYPE_TCMALLOC);
}
base::allocator::thunks::SetGetStatsFunction(get_stats_thunk);
base::allocator::thunks::SetReleaseFreeMemoryFunction(
release_free_memory_thunk);
return 1;
}
......
......@@ -21,6 +21,8 @@
'third_party/nspr/prtime.h',
'third_party/nspr/prcpucfg_linux.h',
'third_party/xdg_mime/xdgmime.h',
'allocator/allocator_extension.cc',
'allocator/allocator_extension.h',
'android/base_jni_registrar.cc',
'android/base_jni_registrar.h',
'android/build_info.cc',
......@@ -589,6 +591,7 @@
},
'dependencies': [
'base_static',
'allocator/allocator.gyp:allocator_extension_thunks',
'../testing/gtest.gyp:gtest_prod',
'../third_party/modp_b64/modp_b64.gyp:modp_b64',
'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
......@@ -808,6 +811,7 @@
},
'dependencies': [
'base_static_win64',
'allocator/allocator.gyp:allocator_extension_thunks_win64',
'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations_win64',
],
# TODO(gregoryd): direct_dependent_settings should be shared with the
......
......@@ -6,6 +6,7 @@
#include <set>
#include "base/allocator/allocator_extension.h"
#include "base/bind.h"
#include "base/threading/thread.h"
#include "chrome/browser/browser_process.h"
......@@ -22,7 +23,6 @@
#include "net/proxy/proxy_service.h"
#include "net/url_request/url_request_context.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::BrowserThread;
......@@ -131,14 +131,12 @@ void MemoryPurger::PurgeBrowser() {
// * Purge AppCache memory. Not yet implemented sufficiently.
// * Browser-side DatabaseTracker. Not implemented sufficiently.
#if !defined(OS_MACOSX) && defined(USE_TCMALLOC)
// Tell tcmalloc to release any free pages it's still holding.
// Tell our allocator to release any free pages it's still holding.
//
// 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
// complete?
MallocExtension::instance()->ReleaseFreeMemory();
#endif
base::allocator::ReleaseFreeMemory();
}
// static
......
......@@ -4,6 +4,7 @@
#include "chrome/renderer/chrome_render_process_observer.h"
#include "base/allocator/allocator_extension.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/file_util.h"
......@@ -35,7 +36,6 @@
#include "net/base/net_module.h"
#include "third_party/sqlite/sqlite3.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/WebCrossOriginPreflightResultCache.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
......@@ -329,10 +329,8 @@ void ChromeRenderProcessObserver::OnPurgeMemory() {
v8::V8::LowMemoryNotification();
#if !defined(OS_MACOSX) && defined(USE_TCMALLOC)
// Tell tcmalloc to release any free pages it's still holding.
MallocExtension::instance()->ReleaseFreeMemory();
#endif
// Tell our allocator to release any free pages it's still holding.
base::allocator::ReleaseFreeMemory();
if (client_)
client_->OnPurgeMemory();
......
......@@ -4,6 +4,7 @@
#include "content/public/app/content_main_runner.h"
#include "base/allocator/allocator_extension.h"
#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/debug/debugger.h"
......@@ -37,6 +38,10 @@
#include "ui/base/win/dpi.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)
#include <atlbase.h>
#include <atlapp.h>
......@@ -314,6 +319,17 @@ class ContentMainRunnerImpl : public content::ContentMainRunner {
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)
virtual int Initialize(HINSTANCE instance,
sandbox::SandboxInterfaceInfo* sandbox_info,
......@@ -343,6 +359,10 @@ class ContentMainRunnerImpl : public content::ContentMainRunner {
#if !defined(OS_MACOSX) && defined(USE_TCMALLOC)
// For tcmalloc, we need to tell it to behave like new.
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
#if !defined(OS_ANDROID)
......
......@@ -4,16 +4,13 @@
#include "content/browser/tcmalloc_internals_request_job.h"
#include "base/allocator/allocator_extension.h"
#include "content/common/child_process_messages.h"
#include "content/public/browser/browser_child_process_host_iterator.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.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 {
// static
......@@ -88,7 +85,7 @@ void AboutTcmalloc(std::string* data) {
// Populate the collector with stats from the local browser process
// and send off requests to all the renderer processes.
char buffer[1024 * 32];
MallocExtension::instance()->GetStats(buffer, sizeof(buffer));
base::allocator::GetStats(buffer, sizeof(buffer));
std::string browser("Browser");
AboutTcmallocOutputs::GetInstance()->SetOutput(browser, buffer);
......
......@@ -4,6 +4,7 @@
#include "content/common/child_thread.h"
#include "base/allocator/allocator_extension.h"
#include "base/command_line.h"
#include "base/message_loop.h"
#include "base/process.h"
......@@ -27,10 +28,6 @@
#include "content/common/handle_enumerator_win.h"
#endif
#if defined(USE_TCMALLOC)
#include "third_party/tcmalloc/chromium/src/gperftools/malloc_extension.h"
#endif
using tracked_objects::ThreadData;
ChildThread::ChildThread() {
......@@ -257,7 +254,7 @@ void ChildThread::OnDumpHandles() {
void ChildThread::OnGetTcmallocStats() {
std::string result;
char buffer[1024 * 32];
MallocExtension::instance()->GetStats(buffer, sizeof(buffer));
base::allocator::GetStats(buffer, sizeof(buffer));
result.append(buffer);
Send(new ChildProcessHostMsg_TcmallocStats(result));
}
......
......@@ -9,6 +9,7 @@
#include <map>
#include <vector>
#include "base/allocator/allocator_extension.h"
#include "base/command_line.h"
#include "base/debug/trace_event.h"
#include "base/lazy_instance.h"
......@@ -64,7 +65,6 @@
#include "media/base/media.h"
#include "net/base/net_errors.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/WebCompositor.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDatabase.h"
......@@ -633,9 +633,8 @@ void RenderThreadImpl::IdleHandler() {
IdleHandlerInForegroundTab();
return;
}
#if !defined(OS_MACOSX) && defined(USE_TCMALLOC)
MallocExtension::instance()->ReleaseFreeMemory();
#endif
base::allocator::ReleaseFreeMemory();
v8::V8::IdleNotification();
......@@ -673,9 +672,7 @@ void RenderThreadImpl::IdleHandlerInForegroundTab() {
// idle pause. We set it proportional to the idle timer delay.
int idle_hint = static_cast<int>(new_delay_ms / 10);
if (cpu_usage < kIdleCPUUsageThresholdInPercents) {
#if !defined(OS_MACOSX) && defined(USE_TCMALLOC)
MallocExtension::instance()->ReleaseFreeMemory();
#endif
base::allocator::ReleaseFreeMemory();
if (v8::V8::IdleNotification(idle_hint)) {
// V8 finished collecting garbage.
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