Home | History | Annotate | Download | only in codeflinger
      1 /* libs/pixelflinger/codeflinger/CodeCache.cpp
      2 **
      3 ** Copyright 2006, The Android Open Source Project
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software
     12 ** distributed under the License is distributed on an "AS IS" BASIS,
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 ** See the License for the specific language governing permissions and
     15 ** limitations under the License.
     16 */
     17 
     18 #define LOG_TAG "CodeCache"
     19 
     20 #include <assert.h>
     21 #include <stdio.h>
     22 #include <stdlib.h>
     23 #include <sys/mman.h>
     24 #include <unistd.h>
     25 
     26 #include <cutils/ashmem.h>
     27 #include <log/log.h>
     28 
     29 #include "CodeCache.h"
     30 
     31 namespace android {
     32 
     33 // ----------------------------------------------------------------------------
     34 
     35 #if defined(__arm__) || defined(__aarch64__)
     36 #include <unistd.h>
     37 #include <errno.h>
     38 #endif
     39 
     40 #if defined(__mips__)
     41 #include <asm/cachectl.h>
     42 #include <errno.h>
     43 #endif
     44 
     45 // ----------------------------------------------------------------------------
     46 // ----------------------------------------------------------------------------
     47 
     48 // A dlmalloc mspace is used to manage the code cache over a mmaped region.
     49 #define HAVE_MMAP 0
     50 #define HAVE_MREMAP 0
     51 #define HAVE_MORECORE 0
     52 #define MALLOC_ALIGNMENT 16
     53 #define MSPACES 1
     54 #define NO_MALLINFO 1
     55 #define ONLY_MSPACES 1
     56 // Custom heap error handling.
     57 #define PROCEED_ON_ERROR 0
     58 static void heap_error(const char* msg, const char* function, void* p);
     59 #define CORRUPTION_ERROR_ACTION(m) \
     60     heap_error("HEAP MEMORY CORRUPTION", __FUNCTION__, NULL)
     61 #define USAGE_ERROR_ACTION(m,p) \
     62     heap_error("ARGUMENT IS INVALID HEAP ADDRESS", __FUNCTION__, p)
     63 
     64 #include "../../../../external/dlmalloc/malloc.c"
     65 
     66 static void heap_error(const char* msg, const char* function, void* p) {
     67     ALOG(LOG_FATAL, LOG_TAG, "@@@ ABORTING: CODE FLINGER: %s IN %s addr=%p",
     68          msg, function, p);
     69     /* So that we can get a memory dump around p */
     70     *((int **) 0xdeadbaad) = (int *) p;
     71 }
     72 
     73 // ----------------------------------------------------------------------------
     74 
     75 static void* gExecutableStore = NULL;
     76 static mspace gMspace = NULL;
     77 const size_t kMaxCodeCacheCapacity = 1024 * 1024;
     78 
     79 static mspace getMspace()
     80 {
     81     if (gExecutableStore == NULL) {
     82         int fd = ashmem_create_region("CodeFlinger code cache",
     83                                       kMaxCodeCacheCapacity);
     84         LOG_ALWAYS_FATAL_IF(fd < 0,
     85                             "Creating code cache, ashmem_create_region "
     86                             "failed with error '%s'", strerror(errno));
     87         gExecutableStore = mmap(NULL, kMaxCodeCacheCapacity,
     88                                 PROT_READ | PROT_WRITE | PROT_EXEC,
     89                                 MAP_PRIVATE, fd, 0);
     90         LOG_ALWAYS_FATAL_IF(gExecutableStore == MAP_FAILED,
     91                             "Creating code cache, mmap failed with error "
     92                             "'%s'", strerror(errno));
     93         close(fd);
     94         gMspace = create_mspace_with_base(gExecutableStore, kMaxCodeCacheCapacity,
     95                                           /*locked=*/ false);
     96         mspace_set_footprint_limit(gMspace, kMaxCodeCacheCapacity);
     97     }
     98     return gMspace;
     99 }
    100 
    101 Assembly::Assembly(size_t size)
    102     : mCount(0), mSize(0)
    103 {
    104     mBase = (uint32_t*)mspace_malloc(getMspace(), size);
    105     LOG_ALWAYS_FATAL_IF(mBase == NULL,
    106                         "Failed to create Assembly of size %zd in executable "
    107                         "store of size %zd", size, kMaxCodeCacheCapacity);
    108     mSize = size;
    109 }
    110 
    111 Assembly::~Assembly()
    112 {
    113     mspace_free(getMspace(), mBase);
    114 }
    115 
    116 void Assembly::incStrong(const void*) const
    117 {
    118     mCount.fetch_add(1, std::memory_order_relaxed);
    119 }
    120 
    121 void Assembly::decStrong(const void*) const
    122 {
    123     if (mCount.fetch_sub(1, std::memory_order_acq_rel) == 1) {
    124         delete this;
    125     }
    126 }
    127 
    128 ssize_t Assembly::size() const
    129 {
    130     if (!mBase) return NO_MEMORY;
    131     return mSize;
    132 }
    133 
    134 uint32_t* Assembly::base() const
    135 {
    136     return mBase;
    137 }
    138 
    139 ssize_t Assembly::resize(size_t newSize)
    140 {
    141     mBase = (uint32_t*)mspace_realloc(getMspace(), mBase, newSize);
    142     LOG_ALWAYS_FATAL_IF(mBase == NULL,
    143                         "Failed to resize Assembly to %zd in code cache "
    144                         "of size %zd", newSize, kMaxCodeCacheCapacity);
    145     mSize = newSize;
    146     return size();
    147 }
    148 
    149 // ----------------------------------------------------------------------------
    150 
    151 CodeCache::CodeCache(size_t size)
    152     : mCacheSize(size), mCacheInUse(0)
    153 {
    154     pthread_mutex_init(&mLock, 0);
    155 }
    156 
    157 CodeCache::~CodeCache()
    158 {
    159     pthread_mutex_destroy(&mLock);
    160 }
    161 
    162 sp<Assembly> CodeCache::lookup(const AssemblyKeyBase& keyBase) const
    163 {
    164     pthread_mutex_lock(&mLock);
    165     sp<Assembly> r;
    166     ssize_t index = mCacheData.indexOfKey(key_t(keyBase));
    167     if (index >= 0) {
    168         const cache_entry_t& e = mCacheData.valueAt(index);
    169         e.when = mWhen++;
    170         r = e.entry;
    171     }
    172     pthread_mutex_unlock(&mLock);
    173     return r;
    174 }
    175 
    176 int CodeCache::cache(  const AssemblyKeyBase& keyBase,
    177                             const sp<Assembly>& assembly)
    178 {
    179     pthread_mutex_lock(&mLock);
    180 
    181     const ssize_t assemblySize = assembly->size();
    182     while (mCacheInUse + assemblySize > mCacheSize) {
    183         // evict the LRU
    184         size_t lru = 0;
    185         size_t count = mCacheData.size();
    186         for (size_t i=0 ; i<count ; i++) {
    187             const cache_entry_t& e = mCacheData.valueAt(i);
    188             if (e.when < mCacheData.valueAt(lru).when) {
    189                 lru = i;
    190             }
    191         }
    192         const cache_entry_t& e = mCacheData.valueAt(lru);
    193         mCacheInUse -= e.entry->size();
    194         mCacheData.removeItemsAt(lru);
    195     }
    196 
    197     ssize_t err = mCacheData.add(key_t(keyBase), cache_entry_t(assembly, mWhen));
    198     if (err >= 0) {
    199         mCacheInUse += assemblySize;
    200         mWhen++;
    201         // synchronize caches...
    202         char* base = reinterpret_cast<char*>(assembly->base());
    203         char* curr = reinterpret_cast<char*>(base + assembly->size());
    204         __builtin___clear_cache(base, curr);
    205     }
    206 
    207     pthread_mutex_unlock(&mLock);
    208     return err;
    209 }
    210 
    211 // ----------------------------------------------------------------------------
    212 
    213 }; // namespace android
    214