12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/memory/discardable_memory.h"
6a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
78bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "base/basictypes.h"
88bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "base/compiler_specific.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/lazy_instance.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/memory/discardable_memory_ashmem.h"
125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/memory/discardable_memory_ashmem_allocator.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/memory/discardable_memory_emulated.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/memory/discardable_memory_malloc.h"
15116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/sys_info.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)namespace base {
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuconst char kAshmemAllocatorName[] = "DiscardableMemoryAshmemAllocator";
21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// For Ashmem, have the DiscardableMemoryManager trigger userspace eviction
23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// when address space usage gets too high (e.g. 512 MBytes).
24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const size_t kAshmemMemoryLimit = 512 * 1024 * 1024;
25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)size_t GetOptimalAshmemRegionSizeForAllocator() {
27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Note that this may do some I/O (without hitting the disk though) so it
28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // should not be called on the critical path.
29116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return base::SysInfo::AmountOfPhysicalMemory() / 8;
30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
31a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Holds the shared state used for allocations.
33cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)struct SharedState {
34cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  SharedState()
356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      : manager(kAshmemMemoryLimit, kAshmemMemoryLimit, TimeDelta::Max()),
36cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        allocator(kAshmemAllocatorName,
37cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                  GetOptimalAshmemRegionSizeForAllocator()) {}
38a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
39cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  internal::DiscardableMemoryManager manager;
40cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  internal::DiscardableMemoryAshmemAllocator allocator;
41a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)};
42cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)LazyInstance<SharedState>::Leaky g_shared_state = LAZY_INSTANCE_INITIALIZER;
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
44a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}  // namespace
45a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// static
47116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool DiscardableMemory::ReduceMemoryUsage() {
48116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return internal::DiscardableMemoryEmulated::ReduceMemoryUsage();
49116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
50116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
51116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// static
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DiscardableMemory::GetSupportedTypes(
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::vector<DiscardableMemoryType>* types) {
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const DiscardableMemoryType supported_types[] = {
555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    DISCARDABLE_MEMORY_TYPE_ASHMEM,
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DISCARDABLE_MEMORY_TYPE_EMULATED,
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DISCARDABLE_MEMORY_TYPE_MALLOC
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  };
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  types->assign(supported_types, supported_types + arraysize(supported_types));
608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// static
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)scoped_ptr<DiscardableMemory> DiscardableMemory::CreateLockedMemoryWithType(
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DiscardableMemoryType type, size_t size) {
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  switch (type) {
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case DISCARDABLE_MEMORY_TYPE_NONE:
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case DISCARDABLE_MEMORY_TYPE_MAC:
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return scoped_ptr<DiscardableMemory>();
695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    case DISCARDABLE_MEMORY_TYPE_ASHMEM: {
70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      SharedState* const shared_state = g_shared_state.Pointer();
715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      scoped_ptr<internal::DiscardableMemoryAshmem> memory(
725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          new internal::DiscardableMemoryAshmem(
73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)              size, &shared_state->allocator, &shared_state->manager));
745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      if (!memory->Initialize())
755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        return scoped_ptr<DiscardableMemory>();
765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      return memory.PassAs<DiscardableMemory>();
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case DISCARDABLE_MEMORY_TYPE_EMULATED: {
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      scoped_ptr<internal::DiscardableMemoryEmulated> memory(
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          new internal::DiscardableMemoryEmulated(size));
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (!memory->Initialize())
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return scoped_ptr<DiscardableMemory>();
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return memory.PassAs<DiscardableMemory>();
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case DISCARDABLE_MEMORY_TYPE_MALLOC: {
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      scoped_ptr<internal::DiscardableMemoryMalloc> memory(
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          new internal::DiscardableMemoryMalloc(size));
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (!memory->Initialize())
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return scoped_ptr<DiscardableMemory>();
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return memory.PassAs<DiscardableMemory>();
94a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
95a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NOTREACHED();
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return scoped_ptr<DiscardableMemory>();
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DiscardableMemory::PurgeForTesting() {
103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  g_shared_state.Pointer()->manager.PurgeAll();
1045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  internal::DiscardableMemoryEmulated::PurgeForTesting();
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace base
108