Merge "Make terminal cache small."

main
Keisuke Kuroyanagi 2013-09-12 05:21:49 +00:00 committed by Android (Google) Code Review
commit 1b80a45e79
5 changed files with 58 additions and 55 deletions

View File

@ -32,6 +32,8 @@
#define MAX_WORD_LENGTH 48 #define MAX_WORD_LENGTH 48
// Must be equal to BinaryDictionary.MAX_RESULTS in Java // Must be equal to BinaryDictionary.MAX_RESULTS in Java
#define MAX_RESULTS 18 #define MAX_RESULTS 18
// The biggest value among MAX_CACHE_DIC_NODE_SIZE, MAX_CACHE_DIC_NODE_SIZE_FOR_SINGLE_POINT, ...
#define MAX_DIC_NODE_PRIORITY_QUEUE_CAPACITY 310
// Must be equal to ProximityInfo.MAX_PROXIMITY_CHARS_SIZE in Java // Must be equal to ProximityInfo.MAX_PROXIMITY_CHARS_SIZE in Java
#define MAX_PROXIMITY_CHARS_SIZE 16 #define MAX_PROXIMITY_CHARS_SIZE 16
#define ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE 2 #define ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE 2
@ -322,13 +324,6 @@ static inline void prof_out(void) {
#define MAX_POINTER_COUNT 1 #define MAX_POINTER_COUNT 1
#define MAX_POINTER_COUNT_G 2 #define MAX_POINTER_COUNT_G 2
// Queue IDs and size for DicNodesCache
#define DIC_NODES_CACHE_INITIAL_QUEUE_ID_ACTIVE 0
#define DIC_NODES_CACHE_INITIAL_QUEUE_ID_NEXT_ACTIVE 1
#define DIC_NODES_CACHE_INITIAL_QUEUE_ID_TERMINAL 2
#define DIC_NODES_CACHE_INITIAL_QUEUE_ID_CACHE_FOR_CONTINUOUS_SUGGESTION 3
#define DIC_NODES_CACHE_PRIORITY_QUEUES_SIZE 4
template<typename T> AK_FORCE_INLINE const T &min(const T &a, const T &b) { return a < b ? a : b; } template<typename T> AK_FORCE_INLINE const T &min(const T &a, const T &b) { return a < b ? a : b; }
template<typename T> AK_FORCE_INLINE const T &max(const T &a, const T &b) { return a > b ? a : b; } template<typename T> AK_FORCE_INLINE const T &max(const T &a, const T &b) { return a > b ? a : b; }

View File

@ -24,20 +24,16 @@
#include "suggest/core/dicnode/dic_node.h" #include "suggest/core/dicnode/dic_node.h"
#include "suggest/core/dicnode/dic_node_release_listener.h" #include "suggest/core/dicnode/dic_node_release_listener.h"
// The biggest value among MAX_CACHE_DIC_NODE_SIZE, MAX_CACHE_DIC_NODE_SIZE_FOR_SINGLE_POINT, ...
#define MAX_DIC_NODE_PRIORITY_QUEUE_CAPACITY 310
namespace latinime { namespace latinime {
class DicNodePriorityQueue : public DicNodeReleaseListener { class DicNodePriorityQueue : public DicNodeReleaseListener {
public: public:
AK_FORCE_INLINE DicNodePriorityQueue() AK_FORCE_INLINE explicit DicNodePriorityQueue(const int capacity)
: MAX_CAPACITY(MAX_DIC_NODE_PRIORITY_QUEUE_CAPACITY), : mCapacity(capacity), mMaxSize(capacity), mDicNodesBuf(),
mMaxSize(MAX_DIC_NODE_PRIORITY_QUEUE_CAPACITY), mDicNodesBuf(), mUnusedNodeIndices(), mUnusedNodeIndices(), mNextUnusedNodeId(0), mDicNodesQueue() {
mNextUnusedNodeId(0), mDicNodesQueue() { mDicNodesBuf.resize(mCapacity + 1);
mDicNodesBuf.resize(MAX_CAPACITY + 1); mUnusedNodeIndices.resize(mCapacity + 1);
mUnusedNodeIndices.resize(MAX_CAPACITY + 1); clearAndResizeToCapacity();
reset();
} }
// Non virtual inline destructor -- never inherit this class // Non virtual inline destructor -- never inherit this class
@ -52,11 +48,12 @@ class DicNodePriorityQueue : public DicNodeReleaseListener {
} }
AK_FORCE_INLINE void setMaxSize(const int maxSize) { AK_FORCE_INLINE void setMaxSize(const int maxSize) {
mMaxSize = min(maxSize, MAX_CAPACITY); ASSERT(maxSize <= mCapacity);
mMaxSize = min(maxSize, mCapacity);
} }
AK_FORCE_INLINE void reset() { AK_FORCE_INLINE void clearAndResizeToCapacity() {
clearAndResize(MAX_CAPACITY); clearAndResize(mCapacity);
} }
AK_FORCE_INLINE void clear() { AK_FORCE_INLINE void clear() {
@ -64,27 +61,19 @@ class DicNodePriorityQueue : public DicNodeReleaseListener {
} }
AK_FORCE_INLINE void clearAndResize(const int maxSize) { AK_FORCE_INLINE void clearAndResize(const int maxSize) {
ASSERT(maxSize <= mCapacity);
while (!mDicNodesQueue.empty()) { while (!mDicNodesQueue.empty()) {
mDicNodesQueue.pop(); mDicNodesQueue.pop();
} }
setMaxSize(maxSize); setMaxSize(maxSize);
for (int i = 0; i < MAX_CAPACITY + 1; ++i) { for (int i = 0; i < mCapacity + 1; ++i) {
mDicNodesBuf[i].remove(); mDicNodesBuf[i].remove();
mDicNodesBuf[i].setReleaseListener(this); mDicNodesBuf[i].setReleaseListener(this);
mUnusedNodeIndices[i] = i == MAX_CAPACITY ? NOT_A_NODE_ID : static_cast<int>(i) + 1; mUnusedNodeIndices[i] = i == mCapacity ? NOT_A_NODE_ID : static_cast<int>(i) + 1;
} }
mNextUnusedNodeId = 0; mNextUnusedNodeId = 0;
} }
AK_FORCE_INLINE DicNode *newDicNode(DicNode *dicNode) {
DicNode *newNode = searchEmptyDicNode();
if (newNode) {
DicNodeUtils::initByCopy(dicNode, newNode);
return newNode;
}
return 0;
}
// Copy // Copy
AK_FORCE_INLINE DicNode *copyPush(DicNode *dicNode) { AK_FORCE_INLINE DicNode *copyPush(DicNode *dicNode) {
return copyPush(dicNode, mMaxSize); return copyPush(dicNode, mMaxSize);
@ -111,12 +100,12 @@ class DicNodePriorityQueue : public DicNodeReleaseListener {
} }
mUnusedNodeIndices[index] = mNextUnusedNodeId; mUnusedNodeIndices[index] = mNextUnusedNodeId;
mNextUnusedNodeId = index; mNextUnusedNodeId = index;
ASSERT(index >= 0 && index < (MAX_CAPACITY + 1)); ASSERT(index >= 0 && index < (mCapacity + 1));
} }
AK_FORCE_INLINE void dump() const { AK_FORCE_INLINE void dump() const {
AKLOGI("\n\n\n\n\n==========================="); AKLOGI("\n\n\n\n\n===========================");
for (int i = 0; i < MAX_CAPACITY + 1; ++i) { for (int i = 0; i < mCapacity + 1; ++i) {
if (mDicNodesBuf[i].isUsed()) { if (mDicNodesBuf[i].isUsed()) {
mDicNodesBuf[i].dump("QUEUE: "); mDicNodesBuf[i].dump("QUEUE: ");
} }
@ -125,7 +114,7 @@ class DicNodePriorityQueue : public DicNodeReleaseListener {
} }
private: private:
DISALLOW_COPY_AND_ASSIGN(DicNodePriorityQueue); DISALLOW_IMPLICIT_CONSTRUCTORS(DicNodePriorityQueue);
static const int NOT_A_NODE_ID = -1; static const int NOT_A_NODE_ID = -1;
AK_FORCE_INLINE static bool compareDicNode(DicNode *left, DicNode *right) { AK_FORCE_INLINE static bool compareDicNode(DicNode *left, DicNode *right) {
@ -139,7 +128,7 @@ class DicNodePriorityQueue : public DicNodeReleaseListener {
}; };
typedef std::priority_queue<DicNode *, std::vector<DicNode *>, DicNodeComparator> DicNodesQueue; typedef std::priority_queue<DicNode *, std::vector<DicNode *>, DicNodeComparator> DicNodesQueue;
const int MAX_CAPACITY; const int mCapacity;
int mMaxSize; int mMaxSize;
std::vector<DicNode> mDicNodesBuf; // of each element of mDicNodesBuf respectively std::vector<DicNode> mDicNodesBuf; // of each element of mDicNodesBuf respectively
std::vector<int> mUnusedNodeIndices; std::vector<int> mUnusedNodeIndices;
@ -163,13 +152,12 @@ class DicNodePriorityQueue : public DicNodeReleaseListener {
} }
AK_FORCE_INLINE DicNode *searchEmptyDicNode() { AK_FORCE_INLINE DicNode *searchEmptyDicNode() {
// TODO: Currently O(n) but should be improved to O(1) if (mCapacity == 0) {
if (MAX_CAPACITY == 0) {
return 0; return 0;
} }
if (mNextUnusedNodeId == NOT_A_NODE_ID) { if (mNextUnusedNodeId == NOT_A_NODE_ID) {
AKLOGI("No unused node found."); AKLOGI("No unused node found.");
for (int i = 0; i < MAX_CAPACITY + 1; ++i) { for (int i = 0; i < mCapacity + 1; ++i) {
AKLOGI("Dump node availability, %d, %d, %d", AKLOGI("Dump node availability, %d, %d, %d",
i, mDicNodesBuf[i].isUsed(), mUnusedNodeIndices[i]); i, mDicNodesBuf[i].isUsed(), mUnusedNodeIndices[i]);
} }
@ -185,7 +173,7 @@ class DicNodePriorityQueue : public DicNodeReleaseListener {
const int index = static_cast<int>(dicNode - &mDicNodesBuf[0]); const int index = static_cast<int>(dicNode - &mDicNodesBuf[0]);
mNextUnusedNodeId = mUnusedNodeIndices[index]; mNextUnusedNodeId = mUnusedNodeIndices[index];
mUnusedNodeIndices[index] = NOT_A_NODE_ID; mUnusedNodeIndices[index] = NOT_A_NODE_ID;
ASSERT(index >= 0 && index < (MAX_CAPACITY + 1)); ASSERT(index >= 0 && index < (mCapacity + 1));
} }
AK_FORCE_INLINE DicNode *pushPoolNodeWithMaxSize(DicNode *dicNode, const int maxSize) { AK_FORCE_INLINE DicNode *pushPoolNodeWithMaxSize(DicNode *dicNode, const int maxSize) {
@ -209,6 +197,15 @@ class DicNodePriorityQueue : public DicNodeReleaseListener {
AK_FORCE_INLINE DicNode *copyPush(DicNode *dicNode, const int maxSize) { AK_FORCE_INLINE DicNode *copyPush(DicNode *dicNode, const int maxSize) {
return pushPoolNodeWithMaxSize(newDicNode(dicNode), maxSize); return pushPoolNodeWithMaxSize(newDicNode(dicNode), maxSize);
} }
AK_FORCE_INLINE DicNode *newDicNode(DicNode *dicNode) {
DicNode *newNode = searchEmptyDicNode();
if (newNode) {
DicNodeUtils::initByCopy(dicNode, newNode);
}
return newNode;
}
}; };
} // namespace latinime } // namespace latinime
#endif // LATINIME_DIC_NODE_PRIORITY_QUEUE_H #endif // LATINIME_DIC_NODE_PRIORITY_QUEUE_H

View File

@ -32,24 +32,29 @@ class DicNode;
class DicNodesCache { class DicNodesCache {
public: public:
AK_FORCE_INLINE DicNodesCache() AK_FORCE_INLINE DicNodesCache()
: mActiveDicNodes(&mDicNodePriorityQueues[DIC_NODES_CACHE_INITIAL_QUEUE_ID_ACTIVE]), : mDicNodePriorityQueue0(MAX_DIC_NODE_PRIORITY_QUEUE_CAPACITY),
mNextActiveDicNodes(&mDicNodePriorityQueues[ mDicNodePriorityQueue1(MAX_DIC_NODE_PRIORITY_QUEUE_CAPACITY),
DIC_NODES_CACHE_INITIAL_QUEUE_ID_NEXT_ACTIVE]), mDicNodePriorityQueue2(MAX_DIC_NODE_PRIORITY_QUEUE_CAPACITY),
mTerminalDicNodes(&mDicNodePriorityQueues[DIC_NODES_CACHE_INITIAL_QUEUE_ID_TERMINAL]), mDicNodePriorityQueueForTerminal(MAX_RESULTS),
mCachedDicNodesForContinuousSuggestion(&mDicNodePriorityQueues[ mActiveDicNodes(&mDicNodePriorityQueue0),
DIC_NODES_CACHE_INITIAL_QUEUE_ID_CACHE_FOR_CONTINUOUS_SUGGESTION]), mNextActiveDicNodes(&mDicNodePriorityQueue1),
mInputIndex(0), mLastCachedInputIndex(0) { mCachedDicNodesForContinuousSuggestion(&mDicNodePriorityQueue2),
} mTerminalDicNodes(&mDicNodePriorityQueueForTerminal),
mInputIndex(0), mLastCachedInputIndex(0) {}
AK_FORCE_INLINE virtual ~DicNodesCache() {} AK_FORCE_INLINE virtual ~DicNodesCache() {}
AK_FORCE_INLINE void reset(const int nextActiveSize, const int terminalSize) { AK_FORCE_INLINE void reset(const int nextActiveSize, const int terminalSize) {
mInputIndex = 0; mInputIndex = 0;
mLastCachedInputIndex = 0; mLastCachedInputIndex = 0;
mActiveDicNodes->reset(); // We want to use the max capacity for the current active dic node queue.
mActiveDicNodes->clearAndResizeToCapacity();
// nextActiveSize is used to limit the next iteration's active dic node size.
mNextActiveDicNodes->clearAndResize(nextActiveSize); mNextActiveDicNodes->clearAndResize(nextActiveSize);
mTerminalDicNodes->clearAndResize(terminalSize); mTerminalDicNodes->clearAndResize(terminalSize);
mCachedDicNodesForContinuousSuggestion->reset(); // We want to use the max capacity for the cached dic nodes that will be used for the
// continuous suggestion.
mCachedDicNodesForContinuousSuggestion->clearAndResizeToCapacity();
} }
AK_FORCE_INLINE void continueSearch() { AK_FORCE_INLINE void continueSearch() {
@ -163,15 +168,20 @@ class DicNodesCache {
mTerminalDicNodes->clear(); mTerminalDicNodes->clear();
} }
DicNodePriorityQueue mDicNodePriorityQueues[DIC_NODES_CACHE_PRIORITY_QUEUES_SIZE]; // Instances
DicNodePriorityQueue mDicNodePriorityQueue0;
DicNodePriorityQueue mDicNodePriorityQueue1;
DicNodePriorityQueue mDicNodePriorityQueue2;
DicNodePriorityQueue mDicNodePriorityQueueForTerminal;
// Active dicNodes currently being expanded. // Active dicNodes currently being expanded.
DicNodePriorityQueue *mActiveDicNodes; DicNodePriorityQueue *mActiveDicNodes;
// Next dicNodes to be expanded. // Next dicNodes to be expanded.
DicNodePriorityQueue *mNextActiveDicNodes; DicNodePriorityQueue *mNextActiveDicNodes;
// Current top terminal dicNodes.
DicNodePriorityQueue *mTerminalDicNodes;
// Cached dicNodes used for continuous suggestion. // Cached dicNodes used for continuous suggestion.
DicNodePriorityQueue *mCachedDicNodesForContinuousSuggestion; DicNodePriorityQueue *mCachedDicNodesForContinuousSuggestion;
// Current top terminal dicNodes.
DicNodePriorityQueue *mTerminalDicNodes;
int mInputIndex; int mInputIndex;
int mLastCachedInputIndex; int mLastCachedInputIndex;
}; };

View File

@ -59,8 +59,9 @@ const DictionaryStructureWithBufferPolicy *DicTraverseSession::getDictionaryStru
return mDictionary->getDictionaryStructurePolicy(); return mDictionary->getDictionaryStructurePolicy();
} }
void DicTraverseSession::resetCache(const int nextActiveCacheSize, const int maxWords) { void DicTraverseSession::resetCache(const int thresholdForNextActiveDicNodes, const int maxWords) {
mDicNodesCache.reset(nextActiveCacheSize, maxWords); mDicNodesCache.reset(thresholdForNextActiveDicNodes /* nextActiveSize */,
maxWords /* terminalSize */);
mMultiBigramMap.clear(); mMultiBigramMap.clear();
mPartiallyCommited = false; mPartiallyCommited = false;
} }

View File

@ -73,7 +73,7 @@ class DicTraverseSession {
const int inputSize, const int *const inputXs, const int *const inputYs, const int inputSize, const int *const inputXs, const int *const inputYs,
const int *const times, const int *const pointerIds, const float maxSpatialDistance, const int *const times, const int *const pointerIds, const float maxSpatialDistance,
const int maxPointerCount); const int maxPointerCount);
void resetCache(const int nextActiveCacheSize, const int maxWords); void resetCache(const int thresholdForNextActiveDicNodes, const int maxWords);
const DictionaryStructureWithBufferPolicy *getDictionaryStructurePolicy() const; const DictionaryStructureWithBufferPolicy *getDictionaryStructurePolicy() const;