blob: 29410c8ab62c662f773ffea1ae2af655a0f0ffa4 [file] [log] [blame]
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001/* 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