CodeCache.cpp revision dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0
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
19#include <assert.h>
20#include <stdio.h>
21#include <stdlib.h>
22
23#include <cutils/log.h>
24#include <cutils/atomic.h>
25
26#include "codeflinger/CodeCache.h"
27
28namespace android {
29
30// ----------------------------------------------------------------------------
31
32#if defined(__arm__)
33#include <unistd.h>
34#include <errno.h>
35#endif
36
37// ----------------------------------------------------------------------------
38
39Assembly::Assembly(size_t size)
40    : mCount(1), mSize(0)
41{
42    mBase = (uint32_t*)malloc(size);
43    if (mBase) {
44        mSize = size;
45    }
46}
47
48Assembly::~Assembly()
49{
50    free(mBase);
51}
52
53void Assembly::incStrong(const void*) const
54{
55    android_atomic_inc(&mCount);
56}
57
58void Assembly::decStrong(const void*) const
59{
60    if (android_atomic_dec(&mCount) == 1) {
61        delete this;
62    }
63}
64
65ssize_t Assembly::size() const
66{
67    if (!mBase) return NO_MEMORY;
68    return mSize;
69}
70
71uint32_t* Assembly::base() const
72{
73    return mBase;
74}
75
76ssize_t Assembly::resize(size_t newSize)
77{
78    mBase = (uint32_t*)realloc(mBase, newSize);
79    mSize = newSize;
80    return size();
81}
82
83// ----------------------------------------------------------------------------
84
85CodeCache::CodeCache(size_t size)
86    : mCacheSize(size), mCacheInUse(0)
87{
88    pthread_mutex_init(&mLock, 0);
89}
90
91CodeCache::~CodeCache()
92{
93    pthread_mutex_destroy(&mLock);
94}
95
96sp<Assembly> CodeCache::lookup(const AssemblyKeyBase& keyBase) const
97{
98    pthread_mutex_lock(&mLock);
99    sp<Assembly> r;
100    ssize_t index = mCacheData.indexOfKey(key_t(keyBase));
101    if (index >= 0) {
102        const cache_entry_t& e = mCacheData.valueAt(index);
103        e.when = mWhen++;
104        r = e.entry;
105    }
106    pthread_mutex_unlock(&mLock);
107    return r;
108}
109
110int CodeCache::cache(  const AssemblyKeyBase& keyBase,
111                            const sp<Assembly>& assembly)
112{
113    pthread_mutex_lock(&mLock);
114
115    const ssize_t assemblySize = assembly->size();
116    while (mCacheInUse + assemblySize > mCacheSize) {
117        // evict the LRU
118        size_t lru = 0;
119        size_t count = mCacheData.size();
120        for (size_t i=0 ; i<count ; i++) {
121            const cache_entry_t& e = mCacheData.valueAt(i);
122            if (e.when < mCacheData.valueAt(lru).when) {
123                lru = i;
124            }
125        }
126        const cache_entry_t& e = mCacheData.valueAt(lru);
127        mCacheInUse -= e.entry->size();
128        mCacheData.removeItemsAt(lru);
129    }
130
131    ssize_t err = mCacheData.add(key_t(keyBase), cache_entry_t(assembly, mWhen));
132    if (err >= 0) {
133        mCacheInUse += assemblySize;
134        mWhen++;
135        // synchronize caches...
136#if defined(__arm__)
137        const long base = long(assembly->base());
138        const long curr = base + long(assembly->size());
139        err = cacheflush(base, curr, 0);
140        LOGE_IF(err, "__ARM_NR_cacheflush error %s\n",
141                strerror(errno));
142#endif
143    }
144
145    pthread_mutex_unlock(&mLock);
146    return err;
147}
148
149// ----------------------------------------------------------------------------
150
151}; // namespace android
152