From 74aea53fd5f8b8515c831fc9a976abfc52f75e4e Mon Sep 17 00:00:00 2001 From: Hieu Hoang Date: Tue, 20 Aug 2013 16:06:48 +0100 Subject: [PATCH 1/5] caching error for compact pt --- moses/TranslationModel/CompactPT/PhraseDictionaryCompact.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/moses/TranslationModel/CompactPT/PhraseDictionaryCompact.cpp b/moses/TranslationModel/CompactPT/PhraseDictionaryCompact.cpp index 8af14dd5d..56dd32c14 100644 --- a/moses/TranslationModel/CompactPT/PhraseDictionaryCompact.cpp +++ b/moses/TranslationModel/CompactPT/PhraseDictionaryCompact.cpp @@ -171,8 +171,6 @@ void PhraseDictionaryCompact::CacheForCleanup(TargetPhraseCollection* tpc) PhraseCache &ref = m_sentenceCache; #endif ref.push_back(tpc); - - ReduceCache(); } void PhraseDictionaryCompact::AddEquivPhrase(const Phrase &source, @@ -197,6 +195,8 @@ void PhraseDictionaryCompact::CleanUpAfterSentenceProcessing(const InputType &so PhraseCache temp; temp.swap(ref); + + ReduceCache(); } } From 9e60195995ad140a87e3dfb51420cf1eed7a530f Mon Sep 17 00:00:00 2001 From: Hieu Hoang Date: Wed, 21 Aug 2013 10:15:29 +0100 Subject: [PATCH 2/5] patch segfault for target phrase caching. Only occurs when multithreading. --- moses/TranslationModel/PhraseDictionary.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/moses/TranslationModel/PhraseDictionary.cpp b/moses/TranslationModel/PhraseDictionary.cpp index 7bb48518c..1fa43e48f 100644 --- a/moses/TranslationModel/PhraseDictionary.cpp +++ b/moses/TranslationModel/PhraseDictionary.cpp @@ -136,7 +136,6 @@ void PhraseDictionary::GetTargetPhraseCollectionBatch(const InputPathList &phras void PhraseDictionary::ReduceCache() const { if (m_cache.size() <= m_maxCacheSize) return; // not full - clock_t t = clock(); // find cutoff for last used time priority_queue< clock_t > lastUsedTimes; @@ -149,6 +148,8 @@ void PhraseDictionary::ReduceCache() const for( size_t i=0; i < lastUsedTimes.size()-m_maxCacheSize/2; i++ ) lastUsedTimes.pop(); clock_t cutoffLastUsedTime = lastUsedTimes.top(); + clock_t t = clock(); + cutoffLastUsedTime = min(cutoffLastUsedTime, t - CLOCKS_PER_SEC * 10 * 60); // 10 minutes // remove all old entries #ifdef WITH_THREADS From b1d7340b78b6e01f79661c7592e54bded3a7b11e Mon Sep 17 00:00:00 2001 From: Kenneth Heafield Date: Wed, 21 Aug 2013 10:16:33 +0100 Subject: [PATCH 3/5] Add --full-tcmalloc to link against the non-minimal tcmalloc library --- Jamroot | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Jamroot b/Jamroot index 1f782261c..90882e396 100644 --- a/Jamroot +++ b/Jamroot @@ -19,7 +19,8 @@ #--with-cmph=/path/to/cmph # #Thread-caching malloc (if present, used for multi-threaded builds by default) -#--without-tcmalloc +#--without-tcmalloc does not compile with tcmalloc even if present +#--full-tcmalloc links against the full version (useful for memory profiling) # #REGRESSION TESTING #--with-regtest=/path/to/moses-reg-test-data @@ -76,8 +77,13 @@ boost 103600 ; external-lib z ; if ! [ option.get "without-tcmalloc" : : "yes" ] && [ test_library "tcmalloc_minimal" ] { - external-lib tcmalloc_minimal ; - requirements += multi:tcmalloc_minimal ; + if [ option.get "full-tcmalloc" : : "yes" ] { + tcmalloc = "tcmalloc" ; + } else { + tcmalloc = "tcmalloc_minimal" ; + } + external-lib $(tcmalloc) ; + requirements += multi:$(tcmalloc) ; } else { echo "Tip: install tcmalloc for faster threading. See BUILD-INSTRUCTIONS.txt for more information." ; } From 37c22cd4da1a07c87f31d2f30d55a8e9bca3f789 Mon Sep 17 00:00:00 2001 From: Kenneth Heafield Date: Wed, 21 Aug 2013 14:29:00 +0100 Subject: [PATCH 4/5] Also use unwind for for tcmalloc --- Jamroot | 7 +++++-- jam-files/sanity.jam | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Jamroot b/Jamroot index 90882e396..b1465e1ce 100644 --- a/Jamroot +++ b/Jamroot @@ -79,11 +79,14 @@ external-lib z ; if ! [ option.get "without-tcmalloc" : : "yes" ] && [ test_library "tcmalloc_minimal" ] { if [ option.get "full-tcmalloc" : : "yes" ] { tcmalloc = "tcmalloc" ; + external-lib unwind ; + external-lib tcmalloc : : unwind ; + requirements += tcmalloc unwind -fno-omit-frame-pointer -fno-omit-frame-pointer ; } else { tcmalloc = "tcmalloc_minimal" ; + external-lib tcmalloc_minimal ; + requirements += multi:$(tcmalloc) ; } - external-lib $(tcmalloc) ; - requirements += multi:$(tcmalloc) ; } else { echo "Tip: install tcmalloc for faster threading. See BUILD-INSTRUCTIONS.txt for more information." ; } diff --git a/jam-files/sanity.jam b/jam-files/sanity.jam index 891bf2eb3..04542409a 100644 --- a/jam-files/sanity.jam +++ b/jam-files/sanity.jam @@ -184,8 +184,8 @@ rule boost ( min-version ) { } #Link normally to a library, but sometimes static isn't installed so fall back to dynamic. -rule external-lib ( name : search-path * ) { - lib $(name) : : [ auto-shared $(name) : "-L"$(search-path) ] $(search-path) ; +rule external-lib ( name : search-path * : deps * ) { + lib $(name) : : [ auto-shared $(name) : "-L"$(search-path) ] $(search-path) $(deps) ; } #Write the current command line to previous.sh. This does not do shell escaping. From fcf426a098f28513330b6eefd2f3a038a762ac73 Mon Sep 17 00:00:00 2001 From: Hieu Hoang Date: Wed, 21 Aug 2013 15:58:17 +0100 Subject: [PATCH 5/5] patch segfault for target phrase caching. Only occurs when multithreading. --- moses/TranslationModel/PhraseDictionary.cpp | 48 ++++++++++--------- moses/TranslationModel/PhraseDictionary.h | 14 ++++-- .../PhraseDictionaryTreeAdaptor.cpp | 6 --- .../RuleTable/PhraseDictionaryOnDisk.cpp | 18 ++----- 4 files changed, 41 insertions(+), 45 deletions(-) diff --git a/moses/TranslationModel/PhraseDictionary.cpp b/moses/TranslationModel/PhraseDictionary.cpp index 1fa43e48f..e0589e22a 100644 --- a/moses/TranslationModel/PhraseDictionary.cpp +++ b/moses/TranslationModel/PhraseDictionary.cpp @@ -43,19 +43,15 @@ const TargetPhraseCollection *PhraseDictionary::GetTargetPhraseCollection(const { const TargetPhraseCollection *ret; if (m_maxCacheSize) { + CacheColl &cache = GetCache(); + size_t hash = hash_value(src); std::map >::iterator iter; - { - // scope of read lock -#ifdef WITH_THREADS - boost::shared_lock read_lock(m_accessLock); -#endif - iter = m_cache.find(hash); - } + iter = cache.find(hash); - if (iter == m_cache.end()) { + if (iter == cache.end()) { // not in cache, need to look up from phrase table ret = GetTargetPhraseCollectionNonCache(src); if (ret) { @@ -63,10 +59,7 @@ const TargetPhraseCollection *PhraseDictionary::GetTargetPhraseCollection(const } std::pair value(ret, clock()); -#ifdef WITH_THREADS - boost::unique_lock lock(m_accessLock); -#endif - m_cache[hash] = value; + cache[hash] = value; } else { // in cache. just use it std::pair &value = iter->second; @@ -135,13 +128,14 @@ void PhraseDictionary::GetTargetPhraseCollectionBatch(const InputPathList &phras void PhraseDictionary::ReduceCache() const { - if (m_cache.size() <= m_maxCacheSize) return; // not full + CacheColl &cache = GetCache(); + if (cache.size() <= m_maxCacheSize) return; // not full // find cutoff for last used time priority_queue< clock_t > lastUsedTimes; std::map >::iterator iter; - iter = m_cache.begin(); - while( iter != m_cache.end() ) { + iter = cache.begin(); + while( iter != cache.end() ) { lastUsedTimes.push( iter->second.second ); iter++; } @@ -149,22 +143,30 @@ void PhraseDictionary::ReduceCache() const lastUsedTimes.pop(); clock_t cutoffLastUsedTime = lastUsedTimes.top(); clock_t t = clock(); - cutoffLastUsedTime = min(cutoffLastUsedTime, t - CLOCKS_PER_SEC * 10 * 60); // 10 minutes // remove all old entries -#ifdef WITH_THREADS - boost::unique_lock lock(m_accessLock); -#endif - - iter = m_cache.begin(); - while( iter != m_cache.end() ) { + iter = cache.begin(); + while( iter != cache.end() ) { if (iter->second.second < cutoffLastUsedTime) { std::map >::iterator iterRemove = iter++; delete iterRemove->second.first; - m_cache.erase(iterRemove); + cache.erase(iterRemove); } else iter++; } VERBOSE(2,"Reduced persistent translation option cache in " << ((clock()-t)/(float)CLOCKS_PER_SEC) << " seconds." << std::endl); } + +PhraseDictionary::CacheColl &PhraseDictionary::GetCache() const +{ + CacheColl *cache; + cache = m_cache.get(); + if (cache == NULL) { + cache = new CacheColl; + m_cache.reset(cache); + } + CHECK(cache); + return *cache; } +} // namespace + diff --git a/moses/TranslationModel/PhraseDictionary.h b/moses/TranslationModel/PhraseDictionary.h index 24bc29b52..f06f22bed 100644 --- a/moses/TranslationModel/PhraseDictionary.h +++ b/moses/TranslationModel/PhraseDictionary.h @@ -32,7 +32,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #ifdef WITH_THREADS #include -#include +#else +#include #endif #include "moses/Phrase.h" @@ -116,14 +117,21 @@ protected: // cache size_t m_maxCacheSize; // 0 = no caching - mutable std::map > m_cache; + + typedef std::map > CacheColl; #ifdef WITH_THREADS //reader-writer lock - mutable boost::shared_mutex m_accessLock; + mutable boost::thread_specific_ptr m_cache; +#else + mutable boost::scoped_ptr m_cache; #endif virtual const TargetPhraseCollection *GetTargetPhraseCollectionNonCache(const Phrase& src) const; void ReduceCache() const; + +protected: + CacheColl &GetCache() const; + }; } diff --git a/moses/TranslationModel/PhraseDictionaryTreeAdaptor.cpp b/moses/TranslationModel/PhraseDictionaryTreeAdaptor.cpp index bf8dddee2..4829c2e7e 100644 --- a/moses/TranslationModel/PhraseDictionaryTreeAdaptor.cpp +++ b/moses/TranslationModel/PhraseDictionaryTreeAdaptor.cpp @@ -34,12 +34,6 @@ PhraseDictionaryTreeAdaptor(const std::string &line) PhraseDictionaryTreeAdaptor::~PhraseDictionaryTreeAdaptor() { - std::map >::const_iterator iter; - for (iter = m_cache.begin(); iter != m_cache.end(); ++iter) { - const std::pair &value = iter->second; - const TargetPhraseCollection *coll = value.first; - delete coll; - } } void PhraseDictionaryTreeAdaptor::Load() diff --git a/moses/TranslationModel/RuleTable/PhraseDictionaryOnDisk.cpp b/moses/TranslationModel/RuleTable/PhraseDictionaryOnDisk.cpp index 9a0979178..d7fc793a0 100644 --- a/moses/TranslationModel/RuleTable/PhraseDictionaryOnDisk.cpp +++ b/moses/TranslationModel/RuleTable/PhraseDictionaryOnDisk.cpp @@ -143,20 +143,16 @@ void PhraseDictionaryOnDisk::GetTargetPhraseCollectionBatch(InputPath &inputPath const TargetPhraseCollection *PhraseDictionaryOnDisk::GetTargetPhraseCollection(const OnDiskPt::PhraseNode *ptNode) const { const TargetPhraseCollection *ret; + if (m_maxCacheSize) { + CacheColl &cache = GetCache(); size_t hash = (size_t) ptNode->GetFilePos(); std::map >::iterator iter; - { - // scope of read lock - #ifdef WITH_THREADS - boost::shared_lock read_lock(m_accessLock); - #endif - iter = m_cache.find(hash); - } + iter = cache.find(hash); - if (iter == m_cache.end()) { + if (iter == cache.end()) { // not in cache, need to look up from phrase table ret = GetTargetPhraseCollectionNonCache(ptNode); if (ret) { @@ -164,11 +160,7 @@ const TargetPhraseCollection *PhraseDictionaryOnDisk::GetTargetPhraseCollection( } std::pair value(ret, clock()); - - #ifdef WITH_THREADS - boost::unique_lock lock(m_accessLock); - #endif - m_cache[hash] = value; + cache[hash] = value; } else { // in cache. just use it