use separate locks for nodes/ways/areas render instructions cache

This commit is contained in:
Hannes Janetzek 2013-01-30 03:56:02 +01:00
parent bb39069af2
commit 836f0ea82b

View File

@ -28,7 +28,7 @@ import android.graphics.Color;
* A RenderTheme defines how ways and nodes are drawn. * A RenderTheme defines how ways and nodes are drawn.
*/ */
public class RenderTheme { public class RenderTheme {
private final static String TAG = RenderTheme.class.getName(); //private final static String TAG = RenderTheme.class.getName();
private static final int MATCHING_CACHE_SIZE = 512; private static final int MATCHING_CACHE_SIZE = 512;
private static final int RENDER_THEME_VERSION = 1; private static final int RENDER_THEME_VERSION = 1;
@ -84,9 +84,17 @@ public class RenderTheme {
private final int mMapBackground; private final int mMapBackground;
private final ArrayList<Rule> mRulesList; private final ArrayList<Rule> mRulesList;
private final LRUCache<MatchingCacheKey, RenderInstructionItem> mMatchingCacheNodes; private final LRUCache<MatchingCacheKey, RenderInstructionItem> mNodesCache;
private final LRUCache<MatchingCacheKey, RenderInstructionItem> mMatchingCacheWay; private final LRUCache<MatchingCacheKey, RenderInstructionItem> mWayCache;
private final LRUCache<MatchingCacheKey, RenderInstructionItem> mMatchingCacheArea; private final LRUCache<MatchingCacheKey, RenderInstructionItem> mAreaCache;
private MatchingCacheKey mAreaCacheKey = new MatchingCacheKey();
private MatchingCacheKey mWayCacheKey = new MatchingCacheKey();
private MatchingCacheKey mNodeCacheKey = new MatchingCacheKey();
private ArrayList<RenderInstruction> mWayInstructionList = new ArrayList<RenderInstruction>(4);
private ArrayList<RenderInstruction> mAreaInstructionList = new ArrayList<RenderInstruction>(4);
private ArrayList<RenderInstruction> mNodeInstructionList = new ArrayList<RenderInstruction>(4);
class RenderInstructionItem { class RenderInstructionItem {
RenderInstructionItem next; RenderInstructionItem next;
@ -100,11 +108,11 @@ public class RenderTheme {
mBaseTextSize = baseTextSize; mBaseTextSize = baseTextSize;
mRulesList = new ArrayList<Rule>(); mRulesList = new ArrayList<Rule>();
mMatchingCacheNodes = new LRUCache<MatchingCacheKey, RenderInstructionItem>( mNodesCache = new LRUCache<MatchingCacheKey, RenderInstructionItem>(
MATCHING_CACHE_SIZE); MATCHING_CACHE_SIZE);
mMatchingCacheWay = new LRUCache<MatchingCacheKey, RenderInstructionItem>( mWayCache = new LRUCache<MatchingCacheKey, RenderInstructionItem>(
MATCHING_CACHE_SIZE); MATCHING_CACHE_SIZE);
mMatchingCacheArea = new LRUCache<MatchingCacheKey, RenderInstructionItem>( mAreaCache = new LRUCache<MatchingCacheKey, RenderInstructionItem>(
MATCHING_CACHE_SIZE); MATCHING_CACHE_SIZE);
} }
@ -113,9 +121,9 @@ public class RenderTheme {
* resources. * resources.
*/ */
public void destroy() { public void destroy() {
mMatchingCacheNodes.clear(); mNodesCache.clear();
mMatchingCacheArea.clear(); mAreaCache.clear();
mMatchingCacheWay.clear(); mWayCache.clear();
for (int i = 0, n = mRulesList.size(); i < n; ++i) { for (int i = 0, n = mRulesList.size(); i < n; ++i) {
mRulesList.get(i).onDestroy(); mRulesList.get(i).onDestroy();
@ -153,7 +161,7 @@ public class RenderTheme {
* ... * ...
* @return ... * @return ...
*/ */
public synchronized RenderInstruction[] matchNode(IRenderCallback renderCallback, public RenderInstruction[] matchNode(IRenderCallback renderCallback,
Tag[] tags, byte zoomLevel) { Tag[] tags, byte zoomLevel) {
// list of renderinsctruction items in cache // list of renderinsctruction items in cache
@ -162,75 +170,77 @@ public class RenderTheme {
// the item matching tags and zoomlevel // the item matching tags and zoomlevel
RenderInstructionItem ri = null; RenderInstructionItem ri = null;
MatchingCacheKey matchingCacheKey = new MatchingCacheKey(tags); synchronized (mNodesCache) {
boolean found = mMatchingCacheNodes.containsKey(matchingCacheKey); MatchingCacheKey cacheKey = mNodeCacheKey; //new MatchingCacheKey(tags);
int zoomMask = 1 << zoomLevel; cacheKey.set(tags);
boolean found = mNodesCache.containsKey(cacheKey);
int zoomMask = 1 << zoomLevel;
if (found) { if (found) {
ris = mMatchingCacheNodes.get(matchingCacheKey); ris = mNodesCache.get(cacheKey);
for (ri = ris; ri != null; ri = ri.next) for (ri = ris; ri != null; ri = ri.next)
if ((ri.zoom & zoomMask) != 0) if ((ri.zoom & zoomMask) != 0)
// cache hit // cache hit
break; break;
} }
if (ri == null) { if (ri == null) {
// cache miss // cache miss
List<RenderInstruction> matches = mMatchingList; List<RenderInstruction> matches = mNodeInstructionList;
matches.clear(); matches.clear();
for (int i = 0, n = mRulesList.size(); i < n; ++i) for (int i = 0, n = mRulesList.size(); i < n; ++i)
mRulesList.get(i).matchNode(renderCallback, tags, zoomLevel, matches); mRulesList.get(i).matchNode(renderCallback, tags, zoomLevel, matches);
int size = matches.size(); int size = matches.size();
// check if same instructions are used in another level // check if same instructions are used in another level
for (ri = ris; ri != null; ri = ri.next) { for (ri = ris; ri != null; ri = ri.next) {
if (size == 0) { if (size == 0) {
if (ri.list != null) if (ri.list != null)
continue;
// both matchinglists are empty
break;
}
if (ri.list == null)
continue; continue;
// both matchinglists are empty if (ri.list.length != size)
break; continue;
}
if (ri.list == null) int i = 0;
continue; for (RenderInstruction r : ri.list) {
if (r != matches.get(i))
if (ri.list.length != size) break;
continue; i++;
}
int i = 0; if (i == size)
for (RenderInstruction r : ri.list) { // both matching lists contain the same items
if (r != matches.get(i))
break; break;
i++;
} }
if (i == size)
// both matching lists contain the same items
break;
}
if (ri != null) { if (ri != null) {
// we found a same matchting list on another zoomlevel // we found a same matchting list on another zoomlevel
ri.zoom |= zoomMask; ri.zoom |= zoomMask;
} else { } else {
ri = new RenderInstructionItem(); ri = new RenderInstructionItem();
ri.zoom = zoomMask; ri.zoom = zoomMask;
if (size > 0) { if (size > 0) {
ri.list = new RenderInstruction[size]; ri.list = new RenderInstruction[size];
matches.toArray(ri.list); matches.toArray(ri.list);
}
// attach this list to the one found for MatchingKey
if (ris != null)
ris.next = ri;
else
mNodesCache.put(new MatchingCacheKey(cacheKey), ri);
} }
// attach this list to the one found for MatchingKey
if (ris != null)
ris.next = ri;
else
mMatchingCacheNodes.put(matchingCacheKey, ri);
} }
} }
if (ri.list != null) if (ri.list != null)
render(renderCallback, ri.list, tags); render(renderCallback, ri.list, tags);
@ -238,10 +248,8 @@ public class RenderTheme {
} }
private int missCnt = 0; //private int missCnt = 0;
private int hitCnt = 0; //private int hitCnt = 0;
private MatchingCacheKey mCacheKey = new MatchingCacheKey();
private ArrayList<RenderInstruction> mMatchingList = new ArrayList<RenderInstruction>(4);
/** /**
* Matches a way with the given parameters against this RenderTheme. * Matches a way with the given parameters against this RenderTheme.
@ -258,7 +266,7 @@ public class RenderTheme {
* ... * ...
* @return currently processed render instructions * @return currently processed render instructions
*/ */
public synchronized RenderInstruction[] matchWay(IRenderCallback renderCallback, public RenderInstruction[] matchWay(IRenderCallback renderCallback,
Tag[] tags, byte zoomLevel, boolean closed, boolean render) { Tag[] tags, byte zoomLevel, boolean closed, boolean render) {
// list of renderinsctruction items in cache // list of renderinsctruction items in cache
@ -266,90 +274,95 @@ public class RenderTheme {
// the item matching tags and zoomlevel // the item matching tags and zoomlevel
RenderInstructionItem ri = null; RenderInstructionItem ri = null;
List<RenderInstruction> matches;
LRUCache<MatchingCacheKey, RenderInstructionItem> matchingCache; LRUCache<MatchingCacheKey, RenderInstructionItem> matchingCache;
MatchingCacheKey matchingCacheKey; MatchingCacheKey cacheKey;
if (closed) { if (closed) {
matchingCache = mMatchingCacheArea; matchingCache = mAreaCache;
cacheKey = mAreaCacheKey;
matches = mAreaInstructionList;
} else { } else {
matchingCache = mMatchingCacheWay; matchingCache = mWayCache;
cacheKey = mWayCacheKey;
matches = mWayInstructionList;
} }
int zoomMask = 1 << zoomLevel; int zoomMask = 1 << zoomLevel;
mCacheKey.set(tags); synchronized (matchingCache) {
ris = matchingCache.get(mCacheKey); cacheKey.set(tags);
ris = matchingCache.get(cacheKey);
for (ri = ris; ri != null; ri = ri.next) for (ri = ris; ri != null; ri = ri.next)
if ((ri.zoom & zoomMask) != 0) if ((ri.zoom & zoomMask) != 0)
// cache hit // cache hit
break; break;
if (ri == null) { if (ri == null) {
// cache miss // cache miss
//Log.d(TAG, missCnt++ + " / " + hitCnt + " Cache Miss"); //Log.d(TAG, missCnt++ + " / " + hitCnt + " Cache Miss");
int c = (closed ? Closed.YES : Closed.NO); int c = (closed ? Closed.YES : Closed.NO);
List<RenderInstruction> matches = mMatchingList; //List<RenderInstruction> matches = mMatchingList;
matches.clear(); matches.clear();
for (int i = 0, n = mRulesList.size(); i < n; ++i) for (int i = 0, n = mRulesList.size(); i < n; ++i)
mRulesList.get(i).matchWay(renderCallback, tags, zoomLevel, c, matches); mRulesList.get(i).matchWay(renderCallback, tags, zoomLevel, c, matches);
int size = matches.size(); int size = matches.size();
// check if same instructions are used in another level // check if same instructions are used in another level
for (ri = ris; ri != null; ri = ri.next) { for (ri = ris; ri != null; ri = ri.next) {
if (size == 0) { if (size == 0) {
if (ri.list != null) if (ri.list != null)
continue;
// both matchinglists are empty
break;
}
if (ri.list == null)
continue; continue;
// both matchinglists are empty if (ri.list.length != size)
break; continue;
}
if (ri.list == null) int i = 0;
continue; for (RenderInstruction r : ri.list) {
if (r != matches.get(i))
if (ri.list.length != size) break;
continue; i++;
}
int i = 0; if (i == size)
for (RenderInstruction r : ri.list) { // both matching lists contain the same items
if (r != matches.get(i))
break; break;
i++;
}
if (i == size)
// both matching lists contain the same items
break;
}
if (ri != null) {
// we found a same matchting list on another zoomlevel
ri.zoom |= zoomMask;
//Log.d(TAG, " same instructions " + size + " " + Arrays.deepToString(tags));
} else {
//Log.d(TAG, " new instructions " + size + " " + Arrays.deepToString(tags));
ri = new RenderInstructionItem();
ri.zoom = zoomMask;
if (size > 0) {
ri.list = new RenderInstruction[size];
matches.toArray(ri.list);
} }
// attach this list to the one found for MatchingKey if (ri != null) {
if (ris != null) { // we found a same matchting list on another zoomlevel
ris.next = ri; ri.zoom |= zoomMask;
} //Log.d(TAG, " same instructions " + size + " " + Arrays.deepToString(tags));
else {
matchingCacheKey = new MatchingCacheKey(mCacheKey); } else {
matchingCache.put(matchingCacheKey, ri); //Log.d(TAG, " new instructions " + size + " " + Arrays.deepToString(tags));
ri = new RenderInstructionItem();
ri.zoom = zoomMask;
if (size > 0) {
ri.list = new RenderInstruction[size];
matches.toArray(ri.list);
}
// attach this list to the one found for MatchingKey
if (ris != null) {
ris.next = ri;
}
else {
matchingCache.put(new MatchingCacheKey(cacheKey), ri);
}
} }
} }
} }
if (render && ri.list != null) { if (render && ri.list != null) {
for (int i = 0, n = ri.list.length; i < n; i++) for (int i = 0, n = ri.list.length; i < n; i++)