Skip to content

Commit 67b38c4

Browse files
Christopher TateXavier Ducrohet
authored andcommitted
Cache resource ID lookups in aapt
This speeds up certain workloads considerably, particularly those involved in buildling apps via the SDK. Windows-based use should particularly benefit from the change. (cherry picked from commit d8dde13) Change-Id: I33835bc64ade77688d41e8bfcd371b0a5f59d8fd
1 parent 23cc5d9 commit 67b38c4

File tree

4 files changed

+148
-5
lines changed

4 files changed

+148
-5
lines changed

tools/aapt/Android.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ LOCAL_SRC_FILES := \
2020
StringPool.cpp \
2121
XMLNode.cpp \
2222
ResourceFilter.cpp \
23+
ResourceIdCache.cpp \
2324
ResourceTable.cpp \
2425
Images.cpp \
2526
Resource.cpp \

tools/aapt/ResourceIdCache.cpp

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
//
2+
// Copyright 2012 The Android Open Source Project
3+
//
4+
// Manage a resource ID cache.
5+
6+
#define LOG_TAG "ResourceIdCache"
7+
8+
#include <utils/String16.h>
9+
#include <utils/Log.h>
10+
#include "ResourceIdCache.h"
11+
#include <map>
12+
using namespace std;
13+
14+
15+
static size_t mHits = 0;
16+
static size_t mMisses = 0;
17+
static size_t mCollisions = 0;
18+
19+
static const size_t MAX_CACHE_ENTRIES = 2048;
20+
static const android::String16 TRUE16("1");
21+
static const android::String16 FALSE16("0");
22+
23+
struct CacheEntry {
24+
// concatenation of the relevant strings into a single instance
25+
android::String16 hashedName;
26+
uint32_t id;
27+
28+
CacheEntry() {}
29+
CacheEntry(const android::String16& name, uint32_t resId) : hashedName(name), id(resId) { }
30+
};
31+
32+
static map< uint32_t, CacheEntry > mIdMap;
33+
34+
35+
// djb2; reasonable choice for strings when collisions aren't particularly important
36+
static inline uint32_t hashround(uint32_t hash, int c) {
37+
return ((hash << 5) + hash) + c; /* hash * 33 + c */
38+
}
39+
40+
static uint32_t hash(const android::String16& hashableString) {
41+
uint32_t hash = 5381;
42+
const char16_t* str = hashableString.string();
43+
while (int c = *str++) hash = hashround(hash, c);
44+
return hash;
45+
}
46+
47+
namespace android {
48+
49+
static inline String16 makeHashableName(const android::String16& package,
50+
const android::String16& type,
51+
const android::String16& name,
52+
bool onlyPublic) {
53+
String16 hashable = String16(name);
54+
hashable += type;
55+
hashable += package;
56+
hashable += (onlyPublic ? TRUE16 : FALSE16);
57+
return hashable;
58+
}
59+
60+
uint32_t ResourceIdCache::lookup(const android::String16& package,
61+
const android::String16& type,
62+
const android::String16& name,
63+
bool onlyPublic) {
64+
const String16 hashedName = makeHashableName(package, type, name, onlyPublic);
65+
const uint32_t hashcode = hash(hashedName);
66+
map<uint32_t, CacheEntry>::iterator item = mIdMap.find(hashcode);
67+
if (item == mIdMap.end()) {
68+
// cache miss
69+
mMisses++;
70+
return 0;
71+
}
72+
73+
// legit match?
74+
if (hashedName == (*item).second.hashedName) {
75+
mHits++;
76+
return (*item).second.id;
77+
}
78+
79+
// collision
80+
mCollisions++;
81+
mIdMap.erase(hashcode);
82+
return 0;
83+
}
84+
85+
// returns the resource ID being stored, for callsite convenience
86+
uint32_t ResourceIdCache::store(const android::String16& package,
87+
const android::String16& type,
88+
const android::String16& name,
89+
bool onlyPublic,
90+
uint32_t resId) {
91+
if (mIdMap.size() < MAX_CACHE_ENTRIES) {
92+
const String16 hashedName = makeHashableName(package, type, name, onlyPublic);
93+
const uint32_t hashcode = hash(hashedName);
94+
mIdMap[hashcode] = CacheEntry(hashedName, resId);
95+
}
96+
return resId;
97+
}
98+
99+
void ResourceIdCache::dump() {
100+
printf("ResourceIdCache dump:\n");
101+
printf("Size: %ld\n", mIdMap.size());
102+
printf("Hits: %ld\n", mHits);
103+
printf("Misses: %ld\n", mMisses);
104+
printf("(Collisions: %ld)\n", mCollisions);
105+
}
106+
107+
}

tools/aapt/ResourceIdCache.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//
2+
// Copyright 2012 The Android Open Source Project
3+
//
4+
// Manage a resource ID cache.
5+
6+
#ifndef RESOURCE_ID_CACHE_H
7+
#define RESOURCE_ID_CACHE_H
8+
9+
namespace android {
10+
class android::String16;
11+
12+
class ResourceIdCache {
13+
public:
14+
static uint32_t lookup(const android::String16& package,
15+
const android::String16& type,
16+
const android::String16& name,
17+
bool onlyPublic);
18+
19+
static uint32_t store(const android::String16& package,
20+
const android::String16& type,
21+
const android::String16& name,
22+
bool onlyPublic,
23+
uint32_t resId);
24+
25+
static void dump(void);
26+
};
27+
28+
}
29+
30+
#endif

tools/aapt/ResourceTable.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "XMLNode.h"
1010
#include "ResourceFilter.h"
11+
#include "ResourceIdCache.h"
1112

1213
#include <androidfw/ResourceTypes.h>
1314
#include <utils/ByteOrder.h>
@@ -1998,6 +1999,9 @@ uint32_t ResourceTable::getResId(const String16& package,
19981999
const String16& name,
19992000
bool onlyPublic) const
20002001
{
2002+
uint32_t id = ResourceIdCache::lookup(package, type, name, onlyPublic);
2003+
if (id != 0) return id; // cache hit
2004+
20012005
sp<Package> p = mPackages.valueFor(package);
20022006
if (p == NULL) return 0;
20032007

@@ -2016,11 +2020,10 @@ uint32_t ResourceTable::getResId(const String16& package,
20162020
}
20172021

20182022
if (Res_INTERNALID(rid)) {
2019-
return rid;
2023+
return ResourceIdCache::store(package, type, name, onlyPublic, rid);
20202024
}
2021-
return Res_MAKEID(p->getAssignedId()-1,
2022-
Res_GETTYPE(rid),
2023-
Res_GETENTRY(rid));
2025+
return ResourceIdCache::store(package, type, name, onlyPublic,
2026+
Res_MAKEID(p->getAssignedId()-1, Res_GETTYPE(rid), Res_GETENTRY(rid)));
20242027
}
20252028

20262029
sp<Type> t = p->getTypes().valueFor(type);
@@ -2029,7 +2032,9 @@ uint32_t ResourceTable::getResId(const String16& package,
20292032
if (c == NULL) return 0;
20302033
int32_t ei = c->getEntryIndex();
20312034
if (ei < 0) return 0;
2032-
return getResId(p, t, ei);
2035+
2036+
return ResourceIdCache::store(package, type, name, onlyPublic,
2037+
getResId(p, t, ei));
20332038
}
20342039

20352040
uint32_t ResourceTable::getResId(const String16& ref,

0 commit comments

Comments
 (0)