diff --git a/map/framework.cpp b/map/framework.cpp index 4930f96da6..6026fc01a1 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -433,9 +433,9 @@ Framework::Framework(FrameworkParams const & params) InitUGC(); LOG(LDEBUG, ("UGC initialized")); - InitSearchAPI(); + InitSearchAPI(params.m_numSearchAPIThreads); LOG(LDEBUG, ("Search API initialized")); - + auto const catalogHeadersProvider = make_shared(*this, m_storage); m_bmManager = make_unique(m_user, BookmarkManager::Callbacks( @@ -1496,7 +1496,7 @@ void Framework::InitUGC() } } -void Framework::InitSearchAPI() +void Framework::InitSearchAPI(size_t numThreads) { ASSERT(!m_searchAPI.get(), ("InitSearchAPI() must be called only once.")); ASSERT(m_infoGetter.get(), ()); @@ -1504,7 +1504,7 @@ void Framework::InitSearchAPI() { m_searchAPI = make_unique(m_featuresFetcher.GetDataSource(), m_storage, *m_infoGetter, - static_cast(*this)); + numThreads, static_cast(*this)); } catch (RootException const & e) { diff --git a/map/framework.hpp b/map/framework.hpp index e74968bb69..7be07a565c 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -143,6 +143,7 @@ struct FrameworkParams { bool m_enableLocalAds = true; bool m_enableDiffs = true; + size_t m_numSearchAPIThreads = 1; FrameworkParams() = default; FrameworkParams(bool enableLocalAds, bool enableDiffs) @@ -525,7 +526,7 @@ public: private: void InitCountryInfoGetter(); void InitUGC(); - void InitSearchAPI(); + void InitSearchAPI(size_t numThreads); void InitDiscoveryManager(); DisplacementModeManager m_displacementModeManager; diff --git a/map/map_tests/search_api_tests.cpp b/map/map_tests/search_api_tests.cpp index e1b5cac7a8..b82de94d85 100644 --- a/map/map_tests/search_api_tests.cpp +++ b/map/map_tests/search_api_tests.cpp @@ -62,7 +62,7 @@ class SearchAPITest : public generator::tests_support::TestWithCustomMwms public: SearchAPITest() : m_infoGetter(CountryInfoReader::CreateCountryInfoGetter(GetPlatform())) - , m_api(m_dataSource, m_storage, *m_infoGetter, m_delegate) + , m_api(m_dataSource, m_storage, *m_infoGetter, 1 /* numThreads */, m_delegate) { } diff --git a/map/search_api.cpp b/map/search_api.cpp index 90205d93f9..e384b543eb 100644 --- a/map/search_api.cpp +++ b/map/search_api.cpp @@ -144,13 +144,14 @@ private: } // namespace SearchAPI::SearchAPI(DataSource & dataSource, storage::Storage const & storage, - storage::CountryInfoGetter const & infoGetter, Delegate & delegate) + storage::CountryInfoGetter const & infoGetter, size_t numThreads, + Delegate & delegate) : m_dataSource(dataSource) , m_storage(storage) , m_infoGetter(infoGetter) , m_delegate(delegate) , m_engine(m_dataSource, GetDefaultCategories(), m_infoGetter, - Engine::Params(languages::GetCurrentTwine() /* locale */, 1 /* params.m_numThreads */)) + Engine::Params(languages::GetCurrentTwine() /* locale */, numThreads)) { } diff --git a/map/search_api.hpp b/map/search_api.hpp index 11cb44196c..24eeae6a0f 100644 --- a/map/search_api.hpp +++ b/map/search_api.hpp @@ -96,7 +96,7 @@ public: }; SearchAPI(DataSource & dataSource, storage::Storage const & storage, - storage::CountryInfoGetter const & infoGetter, Delegate & delegate); + storage::CountryInfoGetter const & infoGetter, size_t numThreads, Delegate & delegate); virtual ~SearchAPI() = default; void OnViewportChanged(m2::RectD const & viewport); diff --git a/search/engine.cpp b/search/engine.cpp index 89a8077ec3..be1f67fc8b 100644 --- a/search/engine.cpp +++ b/search/engine.cpp @@ -136,6 +136,8 @@ void Engine::SetLocale(string const & locale) [locale](Processor & processor) { processor.SetPreferredLocale(locale); }); } +size_t Engine::GetNumThreads() const { return m_threads.size(); } + void Engine::ClearCaches() { PostMessage(Message::TYPE_BROADCAST, [](Processor & processor) { processor.ClearCaches(); }); diff --git a/search/engine.hpp b/search/engine.hpp index d49e09f9db..802c5528f4 100644 --- a/search/engine.hpp +++ b/search/engine.hpp @@ -96,6 +96,9 @@ public: // Sets default locale on all query processors. void SetLocale(std::string const & locale); + // Returns the number of request-processing threads. + size_t GetNumThreads() const; + // Posts request to clear caches to the queue. void ClearCaches(); diff --git a/search/search_quality/assessment_tool/assessment_tool.cpp b/search/search_quality/assessment_tool/assessment_tool.cpp index 5c7f6ed2a2..6789308a70 100644 --- a/search/search_quality/assessment_tool/assessment_tool.cpp +++ b/search/search_quality/assessment_tool/assessment_tool.cpp @@ -16,6 +16,7 @@ DEFINE_string(resources_path, "", "Path to resources directory"); DEFINE_string(data_path, "", "Path to data directory"); DEFINE_string(samples_path, "", "Path to the file with samples to open on startup"); +DEFINE_uint64(num_threads, 4, "Number of search engine threads"); int main(int argc, char ** argv) { @@ -35,6 +36,8 @@ int main(int argc, char ** argv) FrameworkParams params; params.m_enableLocalAds = false; + CHECK_GREATER(FLAGS_num_threads, 0, ()); + params.m_numSearchAPIThreads = FLAGS_num_threads; Framework framework(params); MainView view(framework); diff --git a/search/search_quality/assessment_tool/search_request_runner.cpp b/search/search_quality/assessment_tool/search_request_runner.cpp index 89b781392c..b7246e23bd 100644 --- a/search/search_quality/assessment_tool/search_request_runner.cpp +++ b/search/search_quality/assessment_tool/search_request_runner.cpp @@ -5,6 +5,7 @@ #include "base/assert.hpp" #include "base/logging.hpp" +#include #include #include @@ -44,7 +45,7 @@ void SearchRequestRunner::InitiateBackgroundSearch(size_t from, size_t to) --to; m_backgroundFirstIndex = from; m_backgroundLastIndex = to; - m_numProcessedRequests = 0; + m_backgroundNumProcessed = 0; for (size_t index = from; index <= to; ++index) { @@ -57,26 +58,68 @@ void SearchRequestRunner::InitiateBackgroundSearch(size_t from, size_t to) else { CHECK(m_contexts[index].m_searchState == Context::SearchState::Completed, ()); + ++m_backgroundNumProcessed; } } - m_vitalsInLastBackgroundSearch.clear(); - RunNextBackgroundRequest(m_backgroundTimestamp); + size_t const numThreads = m_framework.GetSearchAPI().GetEngine().GetNumThreads(); + for (size_t i = 0; i < numThreads; ++i) + RunNextBackgroundRequest(m_backgroundTimestamp); +} + +void SearchRequestRunner::ResetForegroundSearch() +{ + CHECK_THREAD_CHECKER(m_threadChecker, ()); + + ++m_foregroundTimestamp; + if (auto handle = m_foregroundQueryHandle.lock()) + handle->Cancel(); +} + +void SearchRequestRunner::ResetBackgroundSearch() +{ + CHECK_THREAD_CHECKER(m_threadChecker, ()); + + ++m_backgroundTimestamp; + + queue().swap(m_backgroundQueue); + m_backgroundNumProcessed = 0; + + bool cancelledAny = false; + for (auto const & entry : m_backgroundQueryHandles) + { + auto handle = entry.second.lock(); + if (handle) + { + handle->Cancel(); + cancelledAny = true; + } + } + m_backgroundQueryHandles.clear(); + + if (cancelledAny) + { + for (size_t index = m_backgroundFirstIndex; index <= m_backgroundLastIndex; ++index) + { + if (m_contexts[index].m_searchState == Context::SearchState::InQueue) + { + m_contexts[index].m_searchState = Context::SearchState::Untouched; + m_updateSampleSearchState(index); + } + } + } + + m_backgroundFirstIndex = kInvalidIndex; + m_backgroundLastIndex = kInvalidIndex; } void SearchRequestRunner::RunNextBackgroundRequest(size_t timestamp) { - // todo(@m) Process in batches instead? + CHECK_THREAD_CHECKER(m_threadChecker, ()); + if (m_backgroundQueue.empty()) - { - LOG(LINFO, ("All requests from", m_backgroundFirstIndex + 1, "to", m_backgroundLastIndex + 1, - "have been processed")); - LOG(LINFO, ("Vital results found:", m_vitalsInLastBackgroundSearch.size(), "out of", - m_backgroundLastIndex - m_backgroundFirstIndex + 1)); - LOG(LINFO, - ("Vital results found for these queries (1-based):", m_vitalsInLastBackgroundSearch)); return; - } + size_t index = m_backgroundQueue.front(); m_backgroundQueue.pop(); @@ -90,7 +133,6 @@ void SearchRequestRunner::RunRequest(size_t index, bool background, size_t times auto const & context = m_contexts[index]; auto const & sample = context.m_sample; - // todo(@m) What if we want multiple threads in engine? auto & engine = m_framework.GetSearchAPI().GetEngine(); search::SearchParams params; @@ -110,7 +152,6 @@ void SearchRequestRunner::RunRequest(size_t index, bool background, size_t times vector const actual(results.begin(), results.end()); matcher.Match(sample, actual, goldenMatching, actualMatching); relevances.resize(actual.size()); - bool foundVital = false; for (size_t i = 0; i < goldenMatching.size(); ++i) { auto const j = goldenMatching[i]; @@ -118,17 +159,9 @@ void SearchRequestRunner::RunRequest(size_t index, bool background, size_t times { CHECK_LESS(j, relevances.size(), ()); relevances[j] = sample.m_results[i].m_relevance; - - if (relevances[j] == search::Sample::Result::Relevance::Vital) - { - foundVital = true; - } } } - if (foundVital) - m_vitalsInLastBackgroundSearch.emplace_back(index + 1); - LOG(LINFO, ("Request number", index + 1, "has been processed in the", background ? "background" : "foreground")); } @@ -180,7 +213,13 @@ void SearchRequestRunner::RunRequest(size_t index, bool background, size_t times } if (background) - RunNextBackgroundRequest(timestamp); + { + ++m_backgroundNumProcessed; + if (m_backgroundNumProcessed == m_backgroundLastIndex - m_backgroundFirstIndex + 1) + PrintBackgroundSearchStats(); + else + RunNextBackgroundRequest(timestamp); + } } if (!background) @@ -189,39 +228,37 @@ void SearchRequestRunner::RunRequest(size_t index, bool background, size_t times }; if (background) - m_backgroundQueryHandle = engine.Search(params); + m_backgroundQueryHandles[index] = engine.Search(params); else m_foregroundQueryHandle = engine.Search(params); } -void SearchRequestRunner::ResetForegroundSearch() +void SearchRequestRunner::PrintBackgroundSearchStats() const { - CHECK_THREAD_CHECKER(m_threadChecker, ()); - - ++m_foregroundTimestamp; - if (auto handle = m_foregroundQueryHandle.lock()) - handle->Cancel(); -} - -void SearchRequestRunner::ResetBackgroundSearch() -{ - CHECK_THREAD_CHECKER(m_threadChecker, ()); - - ++m_backgroundTimestamp; - auto handle = m_backgroundQueryHandle.lock(); - if (!handle) - return; - - handle->Cancel(); + LOG(LINFO, ("All requests from", m_backgroundFirstIndex + 1, "to", m_backgroundLastIndex + 1, + "have been processed")); + vector vitals; + vitals.reserve(m_backgroundLastIndex - m_backgroundFirstIndex + 1); for (size_t index = m_backgroundFirstIndex; index <= m_backgroundLastIndex; ++index) { - if (m_contexts[index].m_searchState == Context::SearchState::InQueue) + auto const & context = m_contexts[index]; + auto const & edits = context.m_foundResultsEdits; + bool foundVital = false; + for (auto const & entry : edits.GetEntries()) { - m_contexts[index].m_searchState = Context::SearchState::Untouched; - m_updateSampleSearchState(index); + if (entry.m_currRelevance == search::Sample::Result::Relevance::Vital) + { + foundVital = true; + break; + } } + + if (foundVital) + vitals.emplace_back(index + 1); } - queue().swap(m_backgroundQueue); + LOG(LINFO, ("Vital results found:", vitals.size(), "out of", + m_backgroundLastIndex - m_backgroundFirstIndex + 1)); + LOG(LINFO, ("Vital results found for these queries (1-based):", vitals)); } diff --git a/search/search_quality/assessment_tool/search_request_runner.hpp b/search/search_quality/assessment_tool/search_request_runner.hpp index 26b304ba38..e1b45bdfb4 100644 --- a/search/search_quality/assessment_tool/search_request_runner.hpp +++ b/search/search_quality/assessment_tool/search_request_runner.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -38,10 +39,13 @@ public: private: static size_t constexpr kInvalidIndex = std::numeric_limits::max(); + // Tries to run the unprocessed request with the smallest index, if there is one. void RunNextBackgroundRequest(size_t timestamp); void RunRequest(size_t index, bool background, size_t timestamp); + void PrintBackgroundSearchStats() const; + Framework & m_framework; DataSource const & m_dataSource; @@ -51,20 +55,16 @@ private: UpdateViewOnResults m_updateViewOnResults; UpdateSampleSearchState m_updateSampleSearchState; - std::weak_ptr m_backgroundQueryHandle; std::weak_ptr m_foregroundQueryHandle; + std::map> m_backgroundQueryHandles; size_t m_foregroundTimestamp = 0; size_t m_backgroundTimestamp = 0; size_t m_backgroundFirstIndex = kInvalidIndex; size_t m_backgroundLastIndex = kInvalidIndex; - std::queue m_backgroundQueue; - - size_t m_numProcessedRequests = 0; - - std::vector m_vitalsInLastBackgroundSearch; + size_t m_backgroundNumProcessed = 0; ThreadChecker m_threadChecker; };