Skip to content

Commit

Permalink
base: Discardable memory types.
Browse files Browse the repository at this point in the history
This adds a DiscardableMemoryType enum and a function that
can be used to select what type of discardable memory to
use. This is generally useful for debugging purposes and
when evaluating the performance of one implementation vs
another.

The unit test framework for discardable memory is improved
slightly by testing every supported type on each platform
rather then just the one specific type.

Furthermore, it allows us to expose ashmem based
discardable memory on ChromeOS in about:flags before we
make it default.

No change in behavior unless the new
--use-discardable-memory=type switch is used.

BUG=327516
TEST=base_unitttest --gtest_filter=DiscardableMemory*
TBR=tomhudson@google.com

Review URL: https://codereview.chromium.org/114923005

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@243532 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
reveman@chromium.org committed Jan 8, 2014
1 parent 5e14a1e commit ed1cca4
Show file tree
Hide file tree
Showing 21 changed files with 407 additions and 129 deletions.
1 change: 1 addition & 0 deletions base/base.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@
'md5.h',
'memory/aligned_memory.cc',
'memory/aligned_memory.h',
'memory/discardable_memory.cc',
'memory/discardable_memory.h',
'memory/discardable_memory_allocator_android.cc',
'memory/discardable_memory_allocator_android.h',
Expand Down
85 changes: 85 additions & 0 deletions base/memory/discardable_memory.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright 2014 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/memory/discardable_memory.h"

#include "base/lazy_instance.h"
#include "base/logging.h"

namespace base {
namespace {

const struct TypeNamePair {
DiscardableMemoryType type;
const char* name;
} kTypeNamePairs[] = {
{ DISCARDABLE_MEMORY_TYPE_ANDROID, "android" },
{ DISCARDABLE_MEMORY_TYPE_MAC, "mac" },
{ DISCARDABLE_MEMORY_TYPE_EMULATED, "emulated" }
};

DiscardableMemoryType g_preferred_type = DISCARDABLE_MEMORY_TYPE_NONE;

struct DefaultPreferredType {
DefaultPreferredType() : value(DISCARDABLE_MEMORY_TYPE_NONE) {
std::vector<DiscardableMemoryType> supported_types;
DiscardableMemory::GetSupportedTypes(&supported_types);
DCHECK(!supported_types.empty());
value = supported_types[0];
}
DiscardableMemoryType value;
};
LazyInstance<DefaultPreferredType>::Leaky g_default_preferred_type =
LAZY_INSTANCE_INITIALIZER;

} // namespace

// static
DiscardableMemoryType DiscardableMemory::GetNamedType(
const std::string& name) {
for (size_t i = 0; i < arraysize(kTypeNamePairs); ++i) {
if (name == kTypeNamePairs[i].name)
return kTypeNamePairs[i].type;
}

return DISCARDABLE_MEMORY_TYPE_NONE;
}

// static
const char* DiscardableMemory::GetTypeName(DiscardableMemoryType type) {
for (size_t i = 0; i < arraysize(kTypeNamePairs); ++i) {
if (type == kTypeNamePairs[i].type)
return kTypeNamePairs[i].name;
}

return "unknown";
}

// static
void DiscardableMemory::SetPreferredType(DiscardableMemoryType type) {
// NONE is a reserved value and not a valid default type.
DCHECK_NE(DISCARDABLE_MEMORY_TYPE_NONE, type);

// Make sure this function is only called once before the first call
// to GetPreferredType().
DCHECK_EQ(DISCARDABLE_MEMORY_TYPE_NONE, g_preferred_type);

g_preferred_type = type;
}

// static
DiscardableMemoryType DiscardableMemory::GetPreferredType() {
if (g_preferred_type == DISCARDABLE_MEMORY_TYPE_NONE)
g_preferred_type = g_default_preferred_type.Get().value;

return g_preferred_type;
}

// static
scoped_ptr<DiscardableMemory> DiscardableMemory::CreateLockedMemory(
size_t size) {
return CreateLockedMemoryWithType(GetPreferredType(), size);
}

} // namespace base
55 changes: 42 additions & 13 deletions base/memory/discardable_memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,27 @@
#ifndef BASE_MEMORY_DISCARDABLE_MEMORY_H_
#define BASE_MEMORY_DISCARDABLE_MEMORY_H_

#include <string>
#include <vector>

#include "base/base_export.h"
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"

namespace base {

enum LockDiscardableMemoryStatus {
DISCARDABLE_MEMORY_FAILED = -1,
DISCARDABLE_MEMORY_PURGED = 0,
DISCARDABLE_MEMORY_SUCCESS = 1
enum DiscardableMemoryType {
DISCARDABLE_MEMORY_TYPE_NONE,
DISCARDABLE_MEMORY_TYPE_ANDROID,
DISCARDABLE_MEMORY_TYPE_MAC,
DISCARDABLE_MEMORY_TYPE_EMULATED
};

enum DiscardableMemoryLockStatus {
DISCARDABLE_MEMORY_LOCK_STATUS_FAILED,
DISCARDABLE_MEMORY_LOCK_STATUS_PURGED,
DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS
};

// Platform abstraction for discardable memory. DiscardableMemory is used to
Expand Down Expand Up @@ -53,19 +63,38 @@ class BASE_EXPORT DiscardableMemory {
public:
virtual ~DiscardableMemory() {}

// Check whether the system supports discardable memory natively. Returns
// false if the support is emulated.
static bool SupportedNatively();
// Gets the discardable memory type with a given name.
static DiscardableMemoryType GetNamedType(const std::string& name);

// Gets the name of a discardable memory type.
static const char* GetTypeName(DiscardableMemoryType type);

// Gets system supported discardable memory types. Default preferred type
// at the front of vector.
static void GetSupportedTypes(std::vector<DiscardableMemoryType>* types);

// Sets the preferred discardable memory type. This overrides the default
// preferred type. Can only be called once prior to GetPreferredType()
// or CreateLockedMemory(). Caller is responsible for correct ordering.
static void SetPreferredType(DiscardableMemoryType type);

// Gets the preferred discardable memory type.
static DiscardableMemoryType GetPreferredType();

// Create a DiscardableMemory instance with specified |type| and |size|.
static scoped_ptr<DiscardableMemory> CreateLockedMemoryWithType(
DiscardableMemoryType type, size_t size);

// Create a DiscardableMemory instance with preferred type and |size|.
static scoped_ptr<DiscardableMemory> CreateLockedMemory(size_t size);

// Locks the memory so that it will not be purged by the system. Returns
// DISCARDABLE_MEMORY_SUCCESS on success. If the return value is
// DISCARDABLE_MEMORY_FAILED then this object should be discarded and
// a new one should be created. If the return value is
// DISCARDABLE_MEMORY_PURGED then the memory is present but any data that
// was in it is gone.
virtual LockDiscardableMemoryStatus Lock() WARN_UNUSED_RESULT = 0;
// DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS on success. If the return value is
// DISCARDABLE_MEMORY_LOCK_STATUS_FAILED then this object should be
// discarded and a new one should be created. If the return value is
// DISCARDABLE_MEMORY_LOCK_STATUS_PURGED then the memory is present but any
// data that was in it is gone.
virtual DiscardableMemoryLockStatus Lock() WARN_UNUSED_RESULT = 0;

// Unlocks the memory so that it can be purged by the system. Must be called
// after every successful lock call.
Expand Down
2 changes: 1 addition & 1 deletion base/memory/discardable_memory_allocator_android.cc
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ class DiscardableMemoryAllocator::DiscardableAshmemChunk
virtual ~DiscardableAshmemChunk();

// DiscardableMemory:
virtual LockDiscardableMemoryStatus Lock() OVERRIDE {
virtual DiscardableMemoryLockStatus Lock() OVERRIDE {
DCHECK(!locked_);
locked_ = true;
return internal::LockAshmemRegion(fd_, offset_, size_, address_);
Expand Down
41 changes: 32 additions & 9 deletions base/memory/discardable_memory_android.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
#include "base/file_util.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/discardable_memory.h"
#include "base/memory/discardable_memory_allocator_android.h"
#include "base/memory/discardable_memory_emulated.h"
#include "third_party/ashmem/ashmem.h"

namespace base {
Expand Down Expand Up @@ -100,14 +100,14 @@ bool CloseAshmemRegion(int fd, size_t size, void* address) {
return close(fd) == 0;
}

LockDiscardableMemoryStatus LockAshmemRegion(int fd,
DiscardableMemoryLockStatus LockAshmemRegion(int fd,
size_t off,
size_t size,
const void* address) {
const int result = ashmem_pin_region(fd, off, size);
DCHECK_EQ(0, mprotect(address, size, PROT_READ | PROT_WRITE));
return result == ASHMEM_WAS_PURGED ?
DISCARDABLE_MEMORY_PURGED : DISCARDABLE_MEMORY_SUCCESS;
return result == ASHMEM_WAS_PURGED ? DISCARDABLE_MEMORY_LOCK_STATUS_PURGED
: DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS;
}

bool UnlockAshmemRegion(int fd, size_t off, size_t size, const void* address) {
Expand All @@ -122,14 +122,37 @@ bool UnlockAshmemRegion(int fd, size_t off, size_t size, const void* address) {
} // namespace internal

// static
bool DiscardableMemory::SupportedNatively() {
return true;
void DiscardableMemory::GetSupportedTypes(
std::vector<DiscardableMemoryType>* types) {
const DiscardableMemoryType supported_types[] = {
DISCARDABLE_MEMORY_TYPE_ANDROID,
DISCARDABLE_MEMORY_TYPE_EMULATED
};
types->assign(supported_types, supported_types + arraysize(supported_types));
}

// static
scoped_ptr<DiscardableMemory> DiscardableMemory::CreateLockedMemory(
size_t size) {
return g_context.Pointer()->allocator.Allocate(size);
scoped_ptr<DiscardableMemory> DiscardableMemory::CreateLockedMemoryWithType(
DiscardableMemoryType type, size_t size) {
switch (type) {
case DISCARDABLE_MEMORY_TYPE_NONE:
case DISCARDABLE_MEMORY_TYPE_MAC:
return scoped_ptr<DiscardableMemory>();
case DISCARDABLE_MEMORY_TYPE_ANDROID: {
return g_context.Pointer()->allocator.Allocate(size);
}
case DISCARDABLE_MEMORY_TYPE_EMULATED: {
scoped_ptr<internal::DiscardableMemoryEmulated> memory(
new internal::DiscardableMemoryEmulated(size));
if (!memory->Initialize())
return scoped_ptr<DiscardableMemory>();

return memory.PassAs<DiscardableMemory>();
}
}

NOTREACHED();
return scoped_ptr<DiscardableMemory>();
}

// static
Expand Down
2 changes: 1 addition & 1 deletion base/memory/discardable_memory_android.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ bool CreateAshmemRegion(const char* name, size_t size, int* fd, void** address);

bool CloseAshmemRegion(int fd, size_t size, void* address);

LockDiscardableMemoryStatus LockAshmemRegion(int fd,
DiscardableMemoryLockStatus LockAshmemRegion(int fd,
size_t offset,
size_t size,
const void* address);
Expand Down
9 changes: 5 additions & 4 deletions base/memory/discardable_memory_emulated.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,20 @@ DiscardableMemoryEmulated::~DiscardableMemoryEmulated() {
}

bool DiscardableMemoryEmulated::Initialize() {
return Lock() == DISCARDABLE_MEMORY_PURGED;
return Lock() == DISCARDABLE_MEMORY_LOCK_STATUS_PURGED;
}

LockDiscardableMemoryStatus DiscardableMemoryEmulated::Lock() {
DiscardableMemoryLockStatus DiscardableMemoryEmulated::Lock() {
DCHECK(!is_locked_);

bool purged = false;
memory_ = g_provider.Pointer()->Acquire(this, &purged);
if (!memory_)
return DISCARDABLE_MEMORY_FAILED;
return DISCARDABLE_MEMORY_LOCK_STATUS_FAILED;

is_locked_ = true;
return purged ? DISCARDABLE_MEMORY_PURGED : DISCARDABLE_MEMORY_SUCCESS;
return purged ? DISCARDABLE_MEMORY_LOCK_STATUS_PURGED
: DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS;
}

void DiscardableMemoryEmulated::Unlock() {
Expand Down
2 changes: 1 addition & 1 deletion base/memory/discardable_memory_emulated.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class DiscardableMemoryEmulated : public DiscardableMemory {
bool Initialize();

// Overridden from DiscardableMemory:
virtual LockDiscardableMemoryStatus Lock() OVERRIDE;
virtual DiscardableMemoryLockStatus Lock() OVERRIDE;
virtual void Unlock() OVERRIDE;
virtual void* Memory() const OVERRIDE;

Expand Down
38 changes: 28 additions & 10 deletions base/memory/discardable_memory_linux.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,42 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/memory/discardable_memory.h"

#include "base/logging.h"
#include "base/memory/discardable_memory_emulated.h"

namespace base {

// static
bool DiscardableMemory::SupportedNatively() {
return false;
void DiscardableMemory::GetSupportedTypes(
std::vector<DiscardableMemoryType>* types) {
const DiscardableMemoryType supported_types[] = {
DISCARDABLE_MEMORY_TYPE_EMULATED
};
types->assign(supported_types, supported_types + arraysize(supported_types));
}

// static
scoped_ptr<DiscardableMemory> DiscardableMemory::CreateLockedMemory(
size_t size) {
scoped_ptr<internal::DiscardableMemoryEmulated> memory(
new internal::DiscardableMemoryEmulated(size));
if (!memory->Initialize())
return scoped_ptr<DiscardableMemory>();

return memory.PassAs<DiscardableMemory>();
scoped_ptr<DiscardableMemory> DiscardableMemory::CreateLockedMemoryWithType(
DiscardableMemoryType type, size_t size) {
switch (type) {
case DISCARDABLE_MEMORY_TYPE_NONE:
case DISCARDABLE_MEMORY_TYPE_ANDROID:
case DISCARDABLE_MEMORY_TYPE_MAC:
return scoped_ptr<DiscardableMemory>();
case DISCARDABLE_MEMORY_TYPE_EMULATED: {
scoped_ptr<internal::DiscardableMemoryEmulated> memory(
new internal::DiscardableMemoryEmulated(size));
if (!memory->Initialize())
return scoped_ptr<DiscardableMemory>();

return memory.PassAs<DiscardableMemory>();
}
}

NOTREACHED();
return scoped_ptr<DiscardableMemory>();
}

// static
Expand Down
Loading

0 comments on commit ed1cca4

Please sign in to comment.