Merge "Change cache capacity depending on the dictionary size."

main
Keisuke Kuroyanagi 2013-09-12 10:38:42 +00:00 committed by Android (Google) Code Review
commit b118a9d729
8 changed files with 48 additions and 21 deletions

View File

@ -43,6 +43,7 @@ public final class BinaryDictionary extends Dictionary {
private long mNativeDict; private long mNativeDict;
private final Locale mLocale; private final Locale mLocale;
private final long mDictSize;
private final int[] mInputCodePoints = new int[MAX_WORD_LENGTH]; private final int[] mInputCodePoints = new int[MAX_WORD_LENGTH];
private final int[] mOutputCodePoints = new int[MAX_WORD_LENGTH * MAX_RESULTS]; private final int[] mOutputCodePoints = new int[MAX_WORD_LENGTH * MAX_RESULTS];
private final int[] mSpaceIndices = new int[MAX_RESULTS]; private final int[] mSpaceIndices = new int[MAX_RESULTS];
@ -62,7 +63,7 @@ public final class BinaryDictionary extends Dictionary {
if (traverseSession == null) { if (traverseSession == null) {
traverseSession = mDicTraverseSessions.get(traverseSessionId); traverseSession = mDicTraverseSessions.get(traverseSessionId);
if (traverseSession == null) { if (traverseSession == null) {
traverseSession = new DicTraverseSession(mLocale, mNativeDict); traverseSession = new DicTraverseSession(mLocale, mNativeDict, mDictSize);
mDicTraverseSessions.put(traverseSessionId, traverseSession); mDicTraverseSessions.put(traverseSessionId, traverseSession);
} }
} }
@ -85,6 +86,7 @@ public final class BinaryDictionary extends Dictionary {
final boolean isUpdatable) { final boolean isUpdatable) {
super(dictType); super(dictType);
mLocale = locale; mLocale = locale;
mDictSize = length;
mNativeSuggestOptions.setUseFullEditDistance(useFullEditDistance); mNativeSuggestOptions.setUseFullEditDistance(useFullEditDistance);
loadDictionary(filename, offset, length, isUpdatable); loadDictionary(filename, offset, length, isUpdatable);
} }

View File

@ -25,16 +25,16 @@ public final class DicTraverseSession {
JniUtils.loadNativeLibrary(); JniUtils.loadNativeLibrary();
} }
private static native long setDicTraverseSessionNative(String locale); private static native long setDicTraverseSessionNative(String locale, long dictSize);
private static native void initDicTraverseSessionNative(long nativeDicTraverseSession, private static native void initDicTraverseSessionNative(long nativeDicTraverseSession,
long dictionary, int[] previousWord, int previousWordLength); long dictionary, int[] previousWord, int previousWordLength);
private static native void releaseDicTraverseSessionNative(long nativeDicTraverseSession); private static native void releaseDicTraverseSessionNative(long nativeDicTraverseSession);
private long mNativeDicTraverseSession; private long mNativeDicTraverseSession;
public DicTraverseSession(Locale locale, long dictionary) { public DicTraverseSession(Locale locale, long dictionary, long dictSize) {
mNativeDicTraverseSession = createNativeDicTraverseSession( mNativeDicTraverseSession = createNativeDicTraverseSession(
locale != null ? locale.toString() : ""); locale != null ? locale.toString() : "", dictSize);
initSession(dictionary); initSession(dictionary);
} }
@ -51,8 +51,8 @@ public final class DicTraverseSession {
mNativeDicTraverseSession, dictionary, previousWord, previousWordLength); mNativeDicTraverseSession, dictionary, previousWord, previousWordLength);
} }
private final long createNativeDicTraverseSession(String locale) { private final long createNativeDicTraverseSession(String locale, long dictSize) {
return setDicTraverseSessionNative(locale); return setDicTraverseSessionNative(locale, dictSize);
} }
private void closeInternal() { private void closeInternal() {

View File

@ -25,8 +25,9 @@
namespace latinime { namespace latinime {
class Dictionary; class Dictionary;
static jlong latinime_setDicTraverseSession(JNIEnv *env, jclass clazz, jstring localeJStr) { static jlong latinime_setDicTraverseSession(JNIEnv *env, jclass clazz, jstring localeJStr,
void *traverseSession = DicTraverseSession::getSessionInstance(env, localeJStr); jlong dictSize) {
void *traverseSession = DicTraverseSession::getSessionInstance(env, localeJStr, dictSize);
return reinterpret_cast<jlong>(traverseSession); return reinterpret_cast<jlong>(traverseSession);
} }
@ -53,7 +54,7 @@ static void latinime_releaseDicTraverseSession(JNIEnv *env, jclass clazz, jlong
static const JNINativeMethod sMethods[] = { static const JNINativeMethod sMethods[] = {
{ {
const_cast<char *>("setDicTraverseSessionNative"), const_cast<char *>("setDicTraverseSessionNative"),
const_cast<char *>("(Ljava/lang/String;)J"), const_cast<char *>("(Ljava/lang/String;J)J"),
reinterpret_cast<void *>(latinime_setDicTraverseSession) reinterpret_cast<void *>(latinime_setDicTraverseSession)
}, },
{ {

View File

@ -32,8 +32,6 @@
#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

View File

@ -23,6 +23,11 @@
namespace latinime { namespace latinime {
// The biggest value among MAX_CACHE_DIC_NODE_SIZE, MAX_CACHE_DIC_NODE_SIZE_FOR_SINGLE_POINT, ...
const int DicNodesCache::LARGE_PRIORITY_QUEUE_CAPACITY = 310;
// Capacity for reducing memory footprint.
const int DicNodesCache::SMALL_PRIORITY_QUEUE_CAPACITY = 100;
/** /**
* Truncates all of the dicNodes so that they start at the given commit point. * Truncates all of the dicNodes so that they start at the given commit point.
* Only called for multi-word typing input. * Only called for multi-word typing input.

View File

@ -31,10 +31,11 @@ class DicNode;
*/ */
class DicNodesCache { class DicNodesCache {
public: public:
AK_FORCE_INLINE DicNodesCache() AK_FORCE_INLINE explicit DicNodesCache(const bool usesLargeCapacityCache)
: mDicNodePriorityQueue0(MAX_DIC_NODE_PRIORITY_QUEUE_CAPACITY), : mUsesLargeCapacityCache(usesLargeCapacityCache),
mDicNodePriorityQueue1(MAX_DIC_NODE_PRIORITY_QUEUE_CAPACITY), mDicNodePriorityQueue0(getCacheCapacity()),
mDicNodePriorityQueue2(MAX_DIC_NODE_PRIORITY_QUEUE_CAPACITY), mDicNodePriorityQueue1(getCacheCapacity()),
mDicNodePriorityQueue2(getCacheCapacity()),
mDicNodePriorityQueueForTerminal(MAX_RESULTS), mDicNodePriorityQueueForTerminal(MAX_RESULTS),
mActiveDicNodes(&mDicNodePriorityQueue0), mActiveDicNodes(&mDicNodePriorityQueue0),
mNextActiveDicNodes(&mDicNodePriorityQueue1), mNextActiveDicNodes(&mDicNodePriorityQueue1),
@ -50,7 +51,8 @@ class DicNodesCache {
// We want to use the max capacity for the current active dic node queue. // We want to use the max capacity for the current active dic node queue.
mActiveDicNodes->clearAndResizeToCapacity(); mActiveDicNodes->clearAndResizeToCapacity();
// nextActiveSize is used to limit the next iteration's active dic node size. // nextActiveSize is used to limit the next iteration's active dic node size.
mNextActiveDicNodes->clearAndResize(nextActiveSize); const int nextActiveSizeFittingToTheCapacity = min(nextActiveSize, getCacheCapacity());
mNextActiveDicNodes->clearAndResize(nextActiveSizeFittingToTheCapacity);
mTerminalDicNodes->clearAndResize(terminalSize); mTerminalDicNodes->clearAndResize(terminalSize);
// We want to use the max capacity for the cached dic nodes that will be used for the // We want to use the max capacity for the cached dic nodes that will be used for the
// continuous suggestion. // continuous suggestion.
@ -162,12 +164,21 @@ class DicNodesCache {
return tmp; return tmp;
} }
AK_FORCE_INLINE int getCacheCapacity() const {
return mUsesLargeCapacityCache ?
LARGE_PRIORITY_QUEUE_CAPACITY : SMALL_PRIORITY_QUEUE_CAPACITY;
}
AK_FORCE_INLINE void resetTemporaryCaches() { AK_FORCE_INLINE void resetTemporaryCaches() {
mActiveDicNodes->clear(); mActiveDicNodes->clear();
mNextActiveDicNodes->clear(); mNextActiveDicNodes->clear();
mTerminalDicNodes->clear(); mTerminalDicNodes->clear();
} }
static const int LARGE_PRIORITY_QUEUE_CAPACITY;
static const int SMALL_PRIORITY_QUEUE_CAPACITY;
const bool mUsesLargeCapacityCache;
// Instances // Instances
DicNodePriorityQueue mDicNodePriorityQueue0; DicNodePriorityQueue mDicNodePriorityQueue0;
DicNodePriorityQueue mDicNodePriorityQueue1; DicNodePriorityQueue mDicNodePriorityQueue1;

View File

@ -23,6 +23,11 @@
namespace latinime { namespace latinime {
// 256K bytes threshold is heuristically used to distinguish dictionaries containing many unigrams
// (e.g. main dictionary) from small dictionaries (e.g. contacts...)
const int DicTraverseSession::DICTIONARY_SIZE_THRESHOLD_TO_USE_LARGE_CACHE_FOR_SUGGESTION =
256 * 1024;
void DicTraverseSession::init(const Dictionary *const dictionary, const int *prevWord, void DicTraverseSession::init(const Dictionary *const dictionary, const int *prevWord,
int prevWordLength, const SuggestOptions *const suggestOptions) { int prevWordLength, const SuggestOptions *const suggestOptions) {
mDictionary = dictionary; mDictionary = dictionary;

View File

@ -37,8 +37,12 @@ class DicTraverseSession {
public: public:
// A factory method for DicTraverseSession // A factory method for DicTraverseSession
static AK_FORCE_INLINE void *getSessionInstance(JNIEnv *env, jstring localeStr) { static AK_FORCE_INLINE void *getSessionInstance(JNIEnv *env, jstring localeStr,
return new DicTraverseSession(env, localeStr); jlong dictSize) {
// To deal with the trade-off between accuracy and memory space, large cache is used for
// dictionaries larger that the threshold
return new DicTraverseSession(env, localeStr,
dictSize >= DICTIONARY_SIZE_THRESHOLD_TO_USE_LARGE_CACHE_FOR_SUGGESTION);
} }
static AK_FORCE_INLINE void initSessionInstance(DicTraverseSession *traverseSession, static AK_FORCE_INLINE void initSessionInstance(DicTraverseSession *traverseSession,
@ -54,10 +58,10 @@ class DicTraverseSession {
delete traverseSession; delete traverseSession;
} }
AK_FORCE_INLINE DicTraverseSession(JNIEnv *env, jstring localeStr) AK_FORCE_INLINE DicTraverseSession(JNIEnv *env, jstring localeStr, bool usesLargeCache)
: mPrevWordPos(NOT_A_VALID_WORD_POS), mProximityInfo(0), : mPrevWordPos(NOT_A_VALID_WORD_POS), mProximityInfo(0),
mDictionary(0), mSuggestOptions(0), mDicNodesCache(), mMultiBigramMap(), mDictionary(0), mSuggestOptions(0), mDicNodesCache(usesLargeCache),
mInputSize(0), mPartiallyCommited(false), mMaxPointerCount(1), mMultiBigramMap(), mInputSize(0), mPartiallyCommited(false), mMaxPointerCount(1),
mMultiWordCostMultiplier(1.0f) { mMultiWordCostMultiplier(1.0f) {
// NOTE: mProximityInfoStates is an array of instances. // NOTE: mProximityInfoStates is an array of instances.
// No need to initialize it explicitly here. // No need to initialize it explicitly here.
@ -181,6 +185,7 @@ class DicTraverseSession {
DISALLOW_IMPLICIT_CONSTRUCTORS(DicTraverseSession); DISALLOW_IMPLICIT_CONSTRUCTORS(DicTraverseSession);
// threshold to start caching // threshold to start caching
static const int CACHE_START_INPUT_LENGTH_THRESHOLD; static const int CACHE_START_INPUT_LENGTH_THRESHOLD;
static const int DICTIONARY_SIZE_THRESHOLD_TO_USE_LARGE_CACHE_FOR_SUGGESTION;
void initializeProximityInfoStates(const int *const inputCodePoints, const int *const inputXs, void initializeProximityInfoStates(const int *const inputCodePoints, const int *const inputXs,
const int *const inputYs, const int *const times, const int *const pointerIds, const int *const inputYs, const int *const times, const int *const pointerIds,
const int inputSize, const float maxSpatialDistance, const int maxPointerCount); const int inputSize, const float maxSpatialDistance, const int maxPointerCount);