From c5acd6e6f7f0a17717146d1947da753e97453173 Mon Sep 17 00:00:00 2001 From: Kajari Ghosh Date: Sun, 1 Apr 2018 19:31:46 -0400 Subject: [PATCH] shared storage with mutex shared lock for reads and unique lock for writes declare cache as object and not pointer in serach engine data to simulate singleton declaration put a lock infront of the clear function to make it threadsafe remove clear function from cache because cache will never get dropped unit tests unit tests and timestamp as part of key cache generations hash the key 500 mb 1000 mb 250 mb rebase against implement-cache --- .../routing_algorithms/routing_base_ch.hpp | 27 ++++-- include/engine/search_engine_data.hpp | 9 +- include/engine/unpacking_cache.hpp | 86 ++++++++++--------- .../routing_algorithms/many_to_many_ch.cpp | 5 +- src/engine/search_engine_data.cpp | 14 +-- unit_tests/engine/unpacking_cache.cpp | 36 ++++---- 6 files changed, 88 insertions(+), 89 deletions(-) diff --git a/include/engine/routing_algorithms/routing_base_ch.hpp b/include/engine/routing_algorithms/routing_base_ch.hpp index dd1d31eed..a5e9a3503 100644 --- a/include/engine/routing_algorithms/routing_base_ch.hpp +++ b/include/engine/routing_algorithms/routing_base_ch.hpp @@ -323,11 +323,16 @@ EdgeDuration calculateEBGNodeAnnotations(const DataFacade &facade, std::get<2>(edge) = true; // mark that this edge will now be processed - if (unpacking_cache.IsEdgeInCache(std::make_tuple( - std::get<0>(edge), std::get<1>(edge), facade.GetExcludeIndex()))) + if (unpacking_cache.IsEdgeInCache(std::make_tuple(std::get<0>(edge), + std::get<1>(edge), + facade.GetExcludeIndex(), + facade.GetTimestamp()))) { - EdgeDuration duration = unpacking_cache.GetDuration(std::make_tuple( - std::get<0>(edge), std::get<1>(edge), facade.GetExcludeIndex())); + EdgeDuration duration = + unpacking_cache.GetDuration(std::make_tuple(std::get<0>(edge), + std::get<1>(edge), + facade.GetExcludeIndex(), + facade.GetTimestamp())); duration_stack.emplace(duration); } else @@ -369,8 +374,10 @@ EdgeDuration calculateEBGNodeAnnotations(const DataFacade &facade, } else { - auto temp = std::make_tuple( - std::get<0>(edge), std::get<1>(edge), facade.GetExcludeIndex()); + auto temp = std::make_tuple(std::get<0>(edge), + std::get<1>(edge), + facade.GetExcludeIndex(), + facade.GetTimestamp()); // compute the duration here and put it onto the duration stack using method // similar to annotatePath but smaller EdgeDuration duration = @@ -391,9 +398,11 @@ EdgeDuration calculateEBGNodeAnnotations(const DataFacade &facade, duration_stack.pop(); EdgeDuration duration = edge1 + edge2; duration_stack.emplace(duration); - unpacking_cache.AddEdge( - std::make_tuple(std::get<0>(edge), std::get<1>(edge), facade.GetExcludeIndex()), - duration); + unpacking_cache.AddEdge(std::make_tuple(std::get<0>(edge), + std::get<1>(edge), + facade.GetExcludeIndex(), + facade.GetTimestamp()), + duration); } } diff --git a/include/engine/search_engine_data.hpp b/include/engine/search_engine_data.hpp index e9ab35bba..67a7c62f5 100644 --- a/include/engine/search_engine_data.hpp +++ b/include/engine/search_engine_data.hpp @@ -6,7 +6,8 @@ #include "util/query_heap.hpp" #include "util/typedefs.hpp" -#include +// #include +#include namespace osrm { @@ -47,7 +48,6 @@ template <> struct SearchEngineData using SearchEngineHeapPtr = boost::thread_specific_ptr; using ManyToManyHeapPtr = boost::thread_specific_ptr; - using UnpackingCachePtr = boost::thread_specific_ptr; static SearchEngineHeapPtr forward_heap_1; static SearchEngineHeapPtr reverse_heap_1; @@ -56,7 +56,8 @@ template <> struct SearchEngineData static SearchEngineHeapPtr forward_heap_3; static SearchEngineHeapPtr reverse_heap_3; static ManyToManyHeapPtr many_to_many_heap; - static UnpackingCachePtr unpacking_cache; + + static UnpackingCache unpacking_cache; void InitializeOrClearFirstThreadLocalStorage(unsigned number_of_nodes); @@ -65,8 +66,6 @@ template <> struct SearchEngineData void InitializeOrClearThirdThreadLocalStorage(unsigned number_of_nodes); void InitializeOrClearManyToManyThreadLocalStorage(unsigned number_of_nodes); - - void InitializeOrClearUnpackingCacheThreadLocalStorage(unsigned timestamp); }; struct MultiLayerDijkstraHeapData diff --git a/include/engine/unpacking_cache.hpp b/include/engine/unpacking_cache.hpp index eb9de8ca9..cba64fcac 100644 --- a/include/engine/unpacking_cache.hpp +++ b/include/engine/unpacking_cache.hpp @@ -2,10 +2,7 @@ #define UNPACKING_CACHE_HPP #include -<<<<<<< HEAD #include -======= ->>>>>>> 68659b398... set up for computing durations while unpacking them #include "../../third_party/compute_detail/lru_cache.hpp" #include "util/typedefs.hpp" @@ -20,13 +17,13 @@ namespace engine { typedef unsigned char ExcludeIndex; typedef unsigned Timestamp; -typedef std::tuple Key; +typedef std::tuple Key; class UnpackingCache { private: - boost::compute::detail::lru_cache, EdgeDuration> m_cache; - unsigned m_current_data_timestamp = 0; + boost::compute::detail::lru_cache m_cache; + boost::shared_mutex m_shared_access; public: // TO FIGURE OUT HOW MANY LINES TO INITIALIZE CACHE TO: @@ -34,62 +31,69 @@ class UnpackingCache // https://github.com/Project-OSRM/osrm-backend/issues/4798#issue-288608332) // LRU CACHE IMPLEMENTATION HAS THESE TWO STORAGE CONTAINERS - // Key is of size: std::uint32_t * 2 + (unsigned char) * 1 + unsigned * 1 - // = 4 * 2 + 1 * 1 + 4 * 1 = 21 + // Key is of size: std::uint32_t * 2 + (unsigned char) * 1 + // = 4 * 2 + 1 * 1 = 9 // map: n * Key + n * EdgeDuration - // = n * 21 bytes + n * std::int32_t - // = n * 21 bytes + n * 4 bytes - // = n * 25 bytes + // = n * 9 bytes + n * std::int32_t + // = n * 9 bytes + n * 4 bytes + // = n * 13 bytes // list: n * Key - // = n * 21 bytes - // Total = n * (25 + 21) = n * 46 bytes + // = n * 9 bytes + // Total = n * (13 + 9) = n * 22 bytes // Total cache size: 500 mb = 500 * 1024 *1024 bytes = 524288000 bytes // Total cache size: 1024 mb = 1024 * 1024 *1024 bytes = 1073741824 bytes // Total cache size: 500 mb = 500 * 1024 *1024 bytes = 524288000 bytes // THREAD LOCAL STORAGE (500 mb) - // Number of lines we need = 524288000 / 46 / number of threads = 11397565 / number of threads - // 16 threads: 11397565 / 16 = 712347 - // 8 threads: 11397565 / 8 = 1424695 - // 4 threads: 11397565 / 4 = 2849391 - // 2 threads: 11397565 / 2 = 5698782 + // Number of lines we need = 524288000 / 22 / number of threads = 23831272 / number of threads + // 16 threads: 23831272 / 16 = 1489454 + // 8 threads: 23831272 / 8 = 2978909 + // 4 threads: 23831272 / 4 = 5957818 + // 2 threads: 23831272 / 2 = 11915636 // THREAD LOCAL STORAGE (1024 mb) - // Number of lines we need = 1073741824 / 46 / number of threads = 23342213 / number of threads - // 16 threads: 23342213 / 16 = 1458888 - // 8 threads: 23342213 / 8 = 2917776 - // 4 threads: 23342213 / 4 = 5835553 - // 2 threads: 23342213 / 2 = 11671106 + // Number of lines we need = 1073741824 / 22 / number of threads = 48806446 / number of threads + // 16 threads: 48806446 / 16 = 3050402 + // 8 threads: 48806446 / 8 = 6100805 + // 4 threads: 48806446 / 4 = 12201611 + // 2 threads: 48806446 / 2 = 24403223 + + // LRU CACHE IMPLEMENTATION HAS THESE TWO STORAGE CONTAINERS + // Key is of size: std::uint32_t * 2 + (unsigned char) * 1 + unsigned * 1 + // = 4 * 2 + 1 * 1 + 4 * 1 = 13 + // map: n * Key + n * EdgeDuration + // = n * 13 bytes + n * std::int32_t + // = n * 13 bytes + n * 4 bytes + // = n * 17 bytes + // list: n * Key + // = n * 13 bytes + // Total = n * (17 + 13) = n * 30 bytes + // Total cache size: 500 mb = 500 * 1024 *1024 bytes = 524288000 bytes + // Total cache size: 1024 mb = 1024 * 1024 *1024 bytes = 1073741824 bytes + // Total cache size: 500 mb = 500 * 1024 *1024 bytes = 524288000 bytes // SHARED STORAGE CACHE - // Number of lines we need for shared storage cache = 524288000 / 20 = 26214400 + // Number of lines for shared storage cache 1024 mb = 524288000 / 30 = 17476266 + // Number of lines for shared storage cache 500 mb = 1073741824 / 30 = 35791394 + // Number of lines for shared storage cache 250 mb = 11397565 / 30 = 379918 - UnpackingCache(unsigned timestamp) : m_cache(11671106), m_current_data_timestamp(timestamp){}; + UnpackingCache() : m_cache(17476266){}; - UnpackingCache(std::size_t cache_size, unsigned timestamp) - : m_cache(cache_size), m_current_data_timestamp(timestamp){}; - - void Clear(unsigned new_data_timestamp) - { - if (m_current_data_timestamp != new_data_timestamp) - { - m_cache.clear(); - m_current_data_timestamp = new_data_timestamp; - } - } - - bool IsEdgeInCache(std::tuple edge) + bool IsEdgeInCache(Key edge) { + boost::shared_lock lock(m_shared_access); return m_cache.contains(edge); } - void AddEdge(std::tuple edge, EdgeDuration duration) + void AddEdge(Key edge, EdgeDuration duration) { + boost::unique_lock lock(m_shared_access); m_cache.insert(edge, duration); } - EdgeDuration GetDuration(std::tuple edge) + EdgeDuration GetDuration(Key edge) { + boost::shared_lock lock(m_shared_access); boost::optional duration = m_cache.get(edge); return duration ? *duration : MAXIMAL_EDGE_DURATION; } @@ -97,4 +101,4 @@ class UnpackingCache } // engine } // osrm -#endif // UNPACKING_CACHE_HPP +#endif // UNPACKING_CACHE_HPP \ No newline at end of file diff --git a/src/engine/routing_algorithms/many_to_many_ch.cpp b/src/engine/routing_algorithms/many_to_many_ch.cpp index 7acf47aa2..9cdcf6656 100644 --- a/src/engine/routing_algorithms/many_to_many_ch.cpp +++ b/src/engine/routing_algorithms/many_to_many_ch.cpp @@ -225,9 +225,6 @@ std::vector manyToManySearch(SearchEngineData &engi std::vector search_space_with_buckets; std::vector packed_leg; - engine_working_data.InitializeOrClearUnpackingCacheThreadLocalStorage( - facade.GetTimestamp()); // always pass in the timestamp and clear if it's different - // Populate buckets with paths from all accessible nodes to destinations via backward searches for (std::uint32_t column_idx = 0; column_idx < target_indices.size(); ++column_idx) { @@ -321,7 +318,7 @@ std::vector manyToManySearch(SearchEngineData &engi ch::calculateEBGNodeAnnotations(facade, packed_leg.begin(), packed_leg.end(), - *engine_working_data.unpacking_cache.get()); + engine_working_data.unpacking_cache); // check the direction of travel to figure out how to calculate the offset to/from // the source/target diff --git a/src/engine/search_engine_data.cpp b/src/engine/search_engine_data.cpp index 70231b6ee..59c92c5fe 100644 --- a/src/engine/search_engine_data.cpp +++ b/src/engine/search_engine_data.cpp @@ -14,7 +14,7 @@ SearchEngineData::SearchEngineHeapPtr SearchEngineData::reverse_heap_2; SearchEngineData::SearchEngineHeapPtr SearchEngineData::forward_heap_3; SearchEngineData::SearchEngineHeapPtr SearchEngineData::reverse_heap_3; SearchEngineData::ManyToManyHeapPtr SearchEngineData::many_to_many_heap; -SearchEngineData::UnpackingCachePtr SearchEngineData::unpacking_cache; +UnpackingCache SearchEngineData::unpacking_cache; void SearchEngineData::InitializeOrClearFirstThreadLocalStorage(unsigned number_of_nodes) { @@ -91,18 +91,6 @@ void SearchEngineData::InitializeOrClearManyToManyThreadLocalStorage(unsigne } } -void SearchEngineData::InitializeOrClearUnpackingCacheThreadLocalStorage(unsigned timestamp) -{ - if (unpacking_cache.get()) - { - unpacking_cache->Clear(timestamp); - } - else - { - unpacking_cache.reset(new UnpackingCache(timestamp)); - } -} - // MLD using MLD = routing_algorithms::mld::Algorithm; SearchEngineData::SearchEngineHeapPtr SearchEngineData::forward_heap_1; diff --git a/unit_tests/engine/unpacking_cache.cpp b/unit_tests/engine/unpacking_cache.cpp index d0a359a07..7a219e874 100644 --- a/unit_tests/engine/unpacking_cache.cpp +++ b/unit_tests/engine/unpacking_cache.cpp @@ -16,9 +16,9 @@ BOOST_AUTO_TEST_CASE(add_edge_and_check_existence) { // Arrange (Setup) unsigned timestamp = 1522782542; - UnpackingCache cache(1, timestamp); + UnpackingCache cache(1); - auto key = std::make_tuple(1, 1, 1); + auto key = std::make_tuple(1, 1, 1, timestamp); auto value = 1; // Act @@ -26,7 +26,7 @@ BOOST_AUTO_TEST_CASE(add_edge_and_check_existence) // Assert BOOST_CHECK(cache.IsEdgeInCache(key) == true); - BOOST_CHECK(cache.IsEdgeInCache(std::make_tuple(2, 2, 2)) == false); + BOOST_CHECK(cache.IsEdgeInCache(std::make_tuple(2, 2, 2, timestamp)) == false); auto result = cache.GetDuration(key); BOOST_CHECK_EQUAL(result, value); @@ -35,13 +35,12 @@ BOOST_AUTO_TEST_CASE(add_edge_and_check_existence) BOOST_AUTO_TEST_CASE(cache_invalidation) { // Arrange (Setup) - unsigned timestamp = 1522782542; - UnpackingCache cache(1, timestamp); + UnpackingCache cache(1); - auto key1 = std::make_tuple(1, 1, 1); + auto key1 = std::make_tuple(1, 1, 1, 1522782542); auto value1 = 1; - auto key2 = std::make_tuple(2, 2, 2); + auto key2 = std::make_tuple(2, 2, 2, 1522782543); auto value2 = 2; // Act @@ -56,31 +55,34 @@ BOOST_AUTO_TEST_CASE(cache_invalidation) BOOST_CHECK_EQUAL(result, value2); } -BOOST_AUTO_TEST_CASE(new_data) +BOOST_AUTO_TEST_CASE(store_generations) { // Arrange (Setup) + UnpackingCache cache(2); + unsigned timestamp1 = 1522782542; unsigned timestamp2 = 1522782543; - UnpackingCache cache(1, timestamp1); - - auto key1 = std::make_tuple(1, 2, 3); + auto key1 = std::make_tuple(1, 1, 1, timestamp1); auto value1 = 1; - auto key2 = std::make_tuple(2, 3, 4); + + auto key2 = std::make_tuple(1, 1, 1, timestamp2); auto value2 = 2; // Act cache.AddEdge(key1, value1); - cache.Clear(timestamp2); cache.AddEdge(key2, value2); // Assert - BOOST_CHECK(cache.IsEdgeInCache(key1) == false); + BOOST_CHECK(cache.IsEdgeInCache(key1) == true); BOOST_CHECK(cache.IsEdgeInCache(key2) == true); - BOOST_CHECK(cache.IsEdgeInCache(std::make_tuple(2, 2, 2)) == false); + BOOST_CHECK(cache.IsEdgeInCache(std::make_tuple(2, 2, 2, timestamp1)) == false); - auto result = cache.GetDuration(key2); - BOOST_CHECK_EQUAL(result, value2); + auto result1 = cache.GetDuration(key1); + BOOST_CHECK_EQUAL(result1, value1); + + auto result2 = cache.GetDuration(key2); + BOOST_CHECK_EQUAL(result2, value2); } BOOST_AUTO_TEST_SUITE_END()