From 6966c342fdc3a17adce437023c871129192f470f Mon Sep 17 00:00:00 2001 From: Jae-Seung Yeom Date: Tue, 6 Feb 2024 15:27:33 -0800 Subject: [PATCH 01/14] add residency subdir --- src/dyad/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dyad/CMakeLists.txt b/src/dyad/CMakeLists.txt index ef83edf7..6a9292db 100644 --- a/src/dyad/CMakeLists.txt +++ b/src/dyad/CMakeLists.txt @@ -7,3 +7,4 @@ add_subdirectory(client) add_subdirectory(service) add_subdirectory(wrapper) add_subdirectory(stream) +add_subdirectory(residency) From 169ce895cb738104f4d581117349161acc12dd86 Mon Sep 17 00:00:00 2001 From: Jae-Seung Yeom Date: Tue, 6 Feb 2024 21:10:50 -0800 Subject: [PATCH 02/14] Add the initial version of residency management logic --- CMakeLists.txt | 19 +++ src/dyad/residency/CMakeLists.txt | 52 +++++++ src/dyad/residency/fcache.cpp | 173 ++++++++++++++++++++++ src/dyad/residency/fcache.hpp | 221 +++++++++++++++++++++++++++++ src/dyad/residency/fcache_impl.hpp | 119 ++++++++++++++++ src/dyad/residency/test_fcache.cpp | 80 +++++++++++ 6 files changed, 664 insertions(+) create mode 100644 src/dyad/residency/CMakeLists.txt create mode 100644 src/dyad/residency/fcache.cpp create mode 100644 src/dyad/residency/fcache.hpp create mode 100644 src/dyad/residency/fcache_impl.hpp create mode 100644 src/dyad/residency/test_fcache.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 6ff3cfec..65681b58 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -300,6 +300,25 @@ include_directories(${CMAKE_SOURCE_DIR}/include) # public header add_subdirectory(src/dyad) #cmake_policy(SET CMP0079 NEW) # In case that we need more control over the target building order +if (DEFINED BOOST_ROOT) + message(STATUS "BOOST_ROOT: " ${BOOST_ROOT}) + set(Boost_NO_SYSTEM_PATHS ON) +else () + if (DEFINED ENV{BOOST_ROOT}) + message(STATUS "ENV BOOST_ROOT: " $ENV{BOOST_ROOT}) + set(Boost_NO_SYSTEM_PATHS ON) + endif () +endif () + +# boost::multi_index is needed and is header-only +find_package(Boost + # HINTS ${BOOST_ROOT} $ENV{BOOST_ROOT} + REQUIRED COMPONENTS) + # regex filesystem system program_options) + +message(STATUS "Boost_INCLUDE_DIRS: " ${Boost_INCLUDE_DIRS}) +message(STATUS "Boost_LIBRARY_DIRS: " ${Boost_LIBRARY_DIRS}) + # Write the configure file configure_file("${CMAKE_SOURCE_DIR}/cmake/configure_files/dyad_config.hpp.in" "${CMAKE_INCLUDE_OUTPUT_DIRECTORY}/dyad/dyad_config.hpp" @ONLY) diff --git a/src/dyad/residency/CMakeLists.txt b/src/dyad/residency/CMakeLists.txt new file mode 100644 index 00000000..4fd7bc22 --- /dev/null +++ b/src/dyad/residency/CMakeLists.txt @@ -0,0 +1,52 @@ +set(DYAD_FCACHE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/fcache.cpp) +set(DYAD_FCACHE_PRIVATE_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/../utils/murmur3.h + ${CMAKE_CURRENT_SOURCE_DIR}/../common/dyad_logging.h) +set(DYAD_FCACHE_PUBLIC_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/fcache.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/fcache_impl.hpp) + + +add_library(${PROJECT_NAME}_fcache SHARED ${DYAD_FCACHE_SRC} + ${DYAD_FCACHE_PRIVATE_HEADERS} ${DYAD_FCACHE_PUBLIC_HEADERS}) +set_target_properties(${PROJECT_NAME}_fcache PROPERTIES CMAKE_INSTALL_RPATH + "${CMAKE_INSTALL_PREFIX}/${DYAD_LIBDIR}") + +if(DYAD_LOGGER STREQUAL "CPP_LOGGER") + target_link_libraries(${PROJECT_NAME}_fcache PRIVATE ${CPP_LOGGER_LIBRARIES}) +endif() +if(DYAD_PROFILER STREQUAL "DLIO_PROFILER") + target_link_libraries(${PROJECT_NAME}_fcache PRIVATE ${DLIO_PROFILER_LIBRARIES}) +endif() + +target_compile_definitions(${PROJECT_NAME}_fcache PUBLIC DYAD_HAS_CONFIG) +target_include_directories(${PROJECT_NAME}_fcache PUBLIC + ${Boost_INCLUDE_DIRS} + $ + $) + +add_executable(test_fcache test_fcache.cpp) +target_compile_definitions(test_fcache PUBLIC DYAD_HAS_CONFIG) +target_link_libraries(test_fcache PUBLIC ${PROJECT_NAME}_fcache) +target_link_libraries(test_fcache PRIVATE ${PROJECT_NAME}_murmur3) + +if(DYAD_LOGGER STREQUAL "CPP_LOGGER") + target_link_libraries(test_fcache PRIVATE ${CPP_LOGGER_LIBRARIES}) +endif() +if(DYAD_PROFILER STREQUAL "DLIO_PROFILER") + target_link_libraries(test_cmp_fcache PRIVATE ${DLIO_PROFILER_LIBRARIES}) +endif() + + +if (TARGET DYAD_CXX_FLAGS_werror) + target_link_libraries(${PROJECT_NAME}_fcache PRIVATE DYAD_CXX_FLAGS_werror) +endif () + +install( + TARGETS ${PROJECT_NAME}_fcache + EXPORT ${DYAD_EXPORTED_TARGETS} + LIBRARY DESTINATION ${DYAD_INSTALL_LIB_DIR} + ARCHIVE DESTINATION ${DYAD_INSTALL_LIB_DIR} + RUNTIME DESTINATION ${DYAD_INSTALL_BIN_DIR} +) +if(NOT "${DYAD_FCACHE_PUBLIC_HEADERS}" STREQUAL "") + dyad_install_headers("${DYAD_FCACHE_PUBLIC_HEADERS}" ${CMAKE_CURRENT_SOURCE_DIR}) +endif() diff --git a/src/dyad/residency/fcache.cpp b/src/dyad/residency/fcache.cpp new file mode 100644 index 00000000..148b2aeb --- /dev/null +++ b/src/dyad/residency/fcache.cpp @@ -0,0 +1,173 @@ +#include +#include + +#define DYAD_UTIL_LOGGER +#include + + +namespace dyad_residency { + +//============================================================================= +// Associative Cache Set +//============================================================================= + +bool Set_LRU::lookup (const std::string& fname, id_iterator_t &it) +{ + id_idx_t& index_id = boost::multi_index::get (m_block_set); + it = index_id.find (fname); + return (it != index_id.end ()); +} + +void Set_LRU::evict (void) +{ // LRU + if (m_block_set.size () == 0) return; + priority_idx_t& index_priority = boost::multi_index::get (m_block_set); + priority_iterator_t it = index_priority.begin (); + DYAD_LOG_INFO (NULL, " %s evicts %s from set %u\n", \ + m_level.c_str (), it->m_id.c_str (), m_id); + index_priority.erase (it); +} + +void Set_LRU::load_and_access (const std::string& fname) +{ + m_num_miss++; + + DYAD_LOG_INFO (NULL, " %s adds %s to set %u\n", \ + m_level.c_str (), fname.c_str (), m_id); + if (m_size == m_block_set.size ()) { + evict (); + } + + m_block_set.insert (Simple_Block (fname)); + m_seqno++; +} + +void Set_LRU::access (id_iterator_t &it) +{ + Simple_Block blk = *it; + m_block_set.erase (it); + m_block_set.insert (blk); + m_seqno++; +} + +bool Set_LRU::access (const std::string& fname) +{ + id_iterator_t it; + if (lookup (fname, it)) { // hit + DYAD_LOG_INFO (NULL, " %s reuses %s from set %u\n", \ + m_level.c_str (), fname.c_str (), m_id); + access (it); + return true; + } else { // miss + load_and_access (fname); + return false; + } +} + +unsigned int Set_LRU::get_priority () +{ + return m_seqno; +} + +std::ostream& Set_LRU::print (std::ostream &os) const +{ + os << "size : " << m_size << std::endl; + os << "num accesses : " << m_seqno<< std::endl; + os << "num misses : " << m_num_miss << std::endl; + os << "blkId : " << std::endl; + + const priority_idx_t& index_priority = boost::multi_index::get (m_block_set); + priority_citerator_t it = index_priority.begin (); + priority_citerator_t itend = index_priority.end (); + + for (; it != itend; it++) { + os << it->m_id << std::endl; + } + return os; +} + +std::ostream& operator<<(std::ostream& os, const Set_LRU & cc) +{ + return cc.print (os); +} + + + +bool Set_Prioritized::lookup (const std::string& fname, id_iterator_t &it) +{ + id_idx_t& index_id = boost::multi_index::get (m_block_set); + it = index_id.find (fname); + return (it != index_id.end ()); +} + +void Set_Prioritized::evict (void) +{ + if (m_block_set.size () == 0) return; + priority_idx_t& index_priority = boost::multi_index::get (m_block_set); + priority_iterator_t it = index_priority.begin (); + DYAD_LOG_INFO (NULL, " %s evicts %s from set %u\n", \ + m_level.c_str (), it->m_id.c_str (), m_id); + index_priority.erase (it); +} + +void Set_Prioritized::load_and_access (const std::string& fname) +{ + m_num_miss++; + + DYAD_LOG_INFO (NULL, " %s adds %s to set %u\n", \ + m_level.c_str (), fname.c_str (), m_id); + if (m_size == m_block_set.size ()) { + evict (); + } + + m_block_set.insert (Ranked_Block (fname, get_priority ())); + m_seqno++; +} + +void Set_Prioritized::access (id_iterator_t &it) +{ + Ranked_Block blk = *it; + // reassigning the priority + blk.m_priority = get_priority (); + m_block_set.erase (it); + m_block_set.insert (blk); + m_seqno++; +} + +bool Set_Prioritized::access (const std::string& fname) +{ + id_iterator_t it; + if (lookup (fname, it)) { // hit + DYAD_LOG_INFO (NULL, " %s reuses %s from set %u\n", \ + m_level.c_str (), fname.c_str (), m_id); + access (it); + return true; + } else { // miss + load_and_access (fname); + return false; + } +} + +unsigned int Set_Prioritized::get_priority () +{ + return m_seqno; +} + +std::ostream& Set_Prioritized::print (std::ostream &os) const +{ + os << "size : " << m_size << std::endl; + os << "num accesses : " << m_seqno<< std::endl; + os << "num misses : " << m_num_miss << std::endl; + os << "priority blkId:" << std::endl; + + const priority_idx_t& index_priority = boost::multi_index::get (m_block_set); + priority_citerator_t it = index_priority.begin (); + priority_citerator_t itend = index_priority.end (); + + for (; it != itend; it++) { + os << it->m_priority << ", " << it->m_id << std::endl; + } + return os; +} + +} // end of namespace dyad_residency diff --git a/src/dyad/residency/fcache.hpp b/src/dyad/residency/fcache.hpp new file mode 100644 index 00000000..4c71bb28 --- /dev/null +++ b/src/dyad/residency/fcache.hpp @@ -0,0 +1,221 @@ +#ifndef DYAD_RESIDENCY_FCACHE_H +#define DYAD_RESIDENCY_FCACHE_H + +#if defined(DYAD_HAS_CONFIG) +#include +#else +#error "no config" +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +namespace dyad_residency { + +//============================================================================= +// Cache Block (cache line) for LRU +//============================================================================= + +struct Simple_Block +{ + std::string m_id; // unique id, file name + + Simple_Block (const std::string& id) + : m_id (id) {} +}; + +struct Ranked_Block +{ + std::string m_id; // unique id, file name + unsigned int m_priority; // priority + + Ranked_Block (const std::string& id, unsigned int priority) + : m_id (id), m_priority (priority) {} +}; + + +//============================================================================= +// Associative Cache Set +//============================================================================= + +class Set_LRU +{ + protected: + struct id{}; + struct priority{}; + typedef boost::multi_index_container< + Simple_Block, + boost::multi_index::indexed_by< + boost::multi_index::hashed_unique, + BOOST_MULTI_INDEX_MEMBER(Simple_Block, std::string, m_id)>, + boost::multi_index::sequenced > + > + > LRU_Blocks; + + typedef boost::multi_index::index::type id_idx_t; + typedef boost::multi_index::index::type::iterator id_iterator_t; + typedef boost::multi_index::index::type::const_iterator id_citerator_t; + + typedef boost::multi_index::index::type priority_idx_t; + typedef boost::multi_index::index::type::iterator priority_iterator_t; + typedef boost::multi_index::index::type::const_iterator priority_citerator_t; + + protected: + /** Cache set capacity (n-way in a set associative cache) in terms of the + * maximum number of blocks */ + unsigned int m_size; + /// Total number of sets in the cache to which this set belongs + unsigned int m_num_sets; + /// Id of this set + unsigned int m_id; + + + /** Current access sequence number. This can be used to calculate the numbeer + * of accesses */ + unsigned int m_seqno; + /** In case of cache miss counter reset, keep a record of the current seqno */ + unsigned int m_seqno0; + /// Number of cache misses + unsigned int m_num_miss; + /// Level info of this cache. e,g., L1, or L2. This does not affect operation + std::string m_level; + + LRU_Blocks m_block_set; + + virtual bool lookup (const std::string& fname, id_iterator_t &it); + virtual void evict (void); + virtual void access (id_iterator_t &it); + virtual void load_and_access (const std::string& fname); + virtual unsigned int get_priority (); + + public: + Set_LRU(unsigned int sz, unsigned int n_sets, unsigned int id) + : m_size (sz), m_num_sets (n_sets), m_id (id), + m_seqno (0u), m_seqno0 (0u), m_num_miss (0u) {} + virtual ~Set_LRU () {} + + unsigned int size (void) const { return m_size; } + unsigned int get_num_access (void) const { return m_seqno - m_seqno0; } + unsigned int get_num_miss (void) const { return m_num_miss; } + void reset_cnts (void) { m_seqno0 = m_seqno; m_num_miss = 0u; } + std::string get_level (void) const { return m_level; } + void set_level (const std::string& level) { m_level = level; } + + /** Access by a block index, and returns true if hit. Otherwise false. + * And there must be a following access at the lower cache layer. */ + virtual bool access (const std::string& fname); + + virtual std::ostream& print (std::ostream &os) const; +}; + +std::ostream& operator<<(std::ostream& os, const Set_LRU & sl); + + +class Set_Prioritized : public Set_LRU +{ + protected: + struct id{}; + struct priority{}; + + typedef boost::multi_index_container< + Ranked_Block, + boost::multi_index::indexed_by< + boost::multi_index::hashed_unique, + BOOST_MULTI_INDEX_MEMBER(Ranked_Block, std::string, m_id)>, + boost::multi_index::ordered_non_unique, + BOOST_MULTI_INDEX_MEMBER(Ranked_Block, unsigned int, m_priority)> + > + > Prio_Blocks; + + typedef boost::multi_index::index::type id_idx_t; + typedef boost::multi_index::index::type::iterator id_iterator_t; + typedef boost::multi_index::index::type::const_iterator id_citerator_t; + + typedef boost::multi_index::index::type priority_idx_t; + typedef boost::multi_index::index::type::iterator priority_iterator_t; + typedef boost::multi_index::index::type::const_iterator priority_citerator_t; + + private: + using Set_LRU::lookup; + using Set_LRU::access; + + protected: + Prio_Blocks m_block_set; + + virtual bool lookup (const std::string& fname, id_iterator_t &it); + virtual void evict (void); + virtual void access (id_iterator_t &it); + virtual void load_and_access (const std::string& fname); + virtual unsigned int get_priority (); + + public: + Set_Prioritized (unsigned int sz, unsigned int n_sets, unsigned int id) + : Set_LRU (sz, n_sets, id) {} + virtual ~Set_Prioritized () {} + virtual bool access (const std::string& fname); + virtual std::ostream& print (std::ostream &os) const; +}; + +std::ostream& operator<<(std::ostream& os, const Set_Prioritized & sp); + +//============================================================================= +// Set Associative Cache +//============================================================================= + +/// Set associative cache model +template +class Cache +{ + public: + using Sets = typename std::vector; + + protected: + unsigned int m_size; ///< Capacity of cache in terms of the number of blocks + unsigned int m_ways; ///< For x-way set-associativity + unsigned int m_num_sets; ///< Number of sets + unsigned int m_seed; ///< Seed used to compute hash in determining cache set + std::string m_level; ///< Level of this cache. e,g., L2. + + Sets m_set; + + unsigned int get_cache_set_id (const std::string& fname) const; + + public: + Cache (unsigned int sz, unsigned int w); + virtual ~Cache () {} + + unsigned int size (void) const { return m_size; } + unsigned int get_num_ways (void) const { return m_ways; } + unsigned int get_num_sets (void) const { return m_num_sets; } + unsigned int get_num_access (void) const; + unsigned int get_num_miss (void) const; + + void reset_cnts (void); + void set_seed (unsigned int seed) { m_seed = seed; } + std::string get_level (void) const { return m_level; } + void set_level (const std::string& level); + + /// Returns true if hit. Otherwise false. + virtual bool access (const std::string& fname); + + std::ostream& print (std::ostream &os) const; +}; + +template +std::ostream& operator<< (std::ostream& os, const Cache & cc); + + +} // end of namespace dyad_residency + +#include + +#endif // DYAD_RESIDENCY_FCACHE_H diff --git a/src/dyad/residency/fcache_impl.hpp b/src/dyad/residency/fcache_impl.hpp new file mode 100644 index 00000000..5c2bbf82 --- /dev/null +++ b/src/dyad/residency/fcache_impl.hpp @@ -0,0 +1,119 @@ +#ifndef DYAD_RESIDENCY_FCACHE_IMPL_H +#define DYAD_RESIDENCY_FCACHE_IMPL_H +#include +#include + + +namespace dyad_residency { + +//============================================================================= +// Cache +//============================================================================= + +template +Cache::Cache (unsigned int sz, unsigned int w) +: m_size (sz), m_ways (w), m_seed (104729u) +{ + if (m_ways == 0) { // fully associative + m_num_sets = 1; + m_ways = m_size; + } else { + m_num_sets = m_size / m_ways; + } + + assert (m_size == m_ways * m_num_sets); + + m_set.reserve (m_num_sets); + for (unsigned int i = 0u; i < m_num_sets; i++) { + m_set.emplace_back (Set (m_ways, m_num_sets, i)); + } +} + +template +unsigned int Cache::get_num_access (void) const +{ + unsigned int tot_num_access = 0u; + for (unsigned int i = 0; i < m_num_sets; i++) { + tot_num_access += m_set[i].get_num_access (); + } + return tot_num_access; +} + +template +unsigned int Cache::get_num_miss (void) const +{ + unsigned int tot_num_miss = 0u; + for (unsigned int i = 0; i < m_num_sets; i++) { + tot_num_miss += m_set[i].get_num_miss (); + } + return tot_num_miss; +} + +template +void Cache::reset_cnts (void) +{ + for (unsigned int i = 0; i < m_num_sets; i++) { + m_set[i].reset_cnts (); + } +} + +template +unsigned int Cache::get_cache_set_id (const std::string& fname) const +{ + uint32_t hash[4] = {0u}; // Output for the hash + + if (fname.empty ()) { + // TODO: report the exception + return 0u; + } + const char* str = fname.c_str (); + + MurmurHash3_x64_128 (str, strlen (str), m_seed, hash); + return (hash[0] ^ hash[1] ^ hash[2] ^ hash[3]) % m_num_sets; +} + +template +bool Cache::access (const std::string& fname) +{ + //const unsigned int set_id = 0u; + //const unsigned int set_id = std::stoi (fname) % m_num_sets; + const unsigned int set_id = get_cache_set_id (fname); + + return m_set[set_id].access (fname); +} + +template +void Cache::set_level (const std::string& level) +{ + m_level = level; + for (unsigned int i = 0; i < m_num_sets; i++) { + m_set[i].set_level (level); + } +} + +template +std::ostream& Cache::print (std::ostream &os) const +{ + os << "==========================================" << std::endl; + os << "size: " << m_size << std::endl; + os << "nAcc: " << get_num_access () << std::endl; + os << "nMiss: " << get_num_miss () << std::endl; + + typename Sets::const_iterator it = m_set.begin (); + typename Sets::const_iterator itend = m_set.end (); + for (unsigned int i = 0; it != itend; it++, i++) { + os << "-------- set "<< i << " ----------" << std::endl; + os << *it << std::endl; + } + os << "==========================================" << std::endl; + return os; +} + +template +std::ostream& operator<< (std::ostream& os, const Cache & cc) +{ + return cc.print (os); +} + +} // end of namespace dyad_residency +#endif // DYAD_RESIDENCY_FCACHE_IMPL_H diff --git a/src/dyad/residency/test_fcache.cpp b/src/dyad/residency/test_fcache.cpp new file mode 100644 index 00000000..249d3ca1 --- /dev/null +++ b/src/dyad/residency/test_fcache.cpp @@ -0,0 +1,80 @@ +#include +#include +#include +#include + +int main (int argc, char** argv) +{ + using namespace dyad_residency; + + int seed = 0; + + if (argc > 2) { + return EXIT_FAILURE; + } + if (argc == 2) { + seed = atoi (argv[1]); + } + + typedef std::vector access; + access acc; // access pattern in terms of the block index + acc.push_back ("1"); + acc.push_back ("4"); + acc.push_back ("2"); + acc.push_back ("3"); + acc.push_back ("5"); + acc.push_back ("5"); + acc.push_back ("3"); + bool hitL1; + +#if 1 + Cache cacheL1 (4, 2); // 2-way set-associative + Cache cacheL2 (8, 2); // cache capacity = 8 blocks +#else + Cache cacheL1 (4, 0); // cache capacity = 4 blocks + Cache cacheL2 (8, 0); // fully-associative +#endif + cacheL1.set_seed (seed + 104677u); + cacheL1.set_level ("L1"); + cacheL2.set_seed (seed + 104681u); + cacheL2.set_level (" L2"); + + std::cout << "L1 Cache size set to " << cacheL1.size () << " blocks" << std::endl; + std::cout << "L2 Cache size set to " << cacheL2.size () << " blocks" << std::endl; + + std::cout << "accessing block 1, 4, 2, and 3 in order" << std::endl; + for (unsigned int i = 0; (i < cacheL1.size ()) && (i < acc.size ()); i++) { + hitL1 = cacheL1.access (acc[i]); + if (!hitL1) cacheL2.access (acc[i]); + } + + std::cout << "-------------------------L1----------------------------" << std::endl; + std::cout << cacheL1 << std::endl; + std::cout << "-------------------------L2----------------------------" << std::endl; + std::cout << cacheL2 << std::endl; + std::cout << "-------------------------------------------------------" << std::endl; + + std::cout << "accessing block 5" << std::endl; + hitL1 = cacheL1.access (acc[4]); + if (!hitL1) cacheL2.access (acc[4]); + + std::cout << "-------------------------L1----------------------------" << std::endl; + std::cout << cacheL1 << std::endl; + std::cout << "-------------------------L2----------------------------" << std::endl; + std::cout << cacheL2 << std::endl; + std::cout << "-------------------------------------------------------" << std::endl; + + std::cout << "accessing block 1, 4, 2, 3, 5, 5, and 3 in order" << std::endl; + for (unsigned int i = 0; i < acc.size (); i++) { + hitL1 = cacheL1.access (acc[i]); + if (!hitL1) cacheL2.access (acc[i]); + } + + std::cout << "-------------------------L1----------------------------" << std::endl; + std::cout << cacheL1 << std::endl; + std::cout << "-------------------------L2----------------------------" << std::endl; + std::cout << cacheL2 << std::endl; + std::cout << "-------------------------------------------------------" << std::endl; + + return EXIT_SUCCESS; +} From 518b0fd40cecc6487e5cda81f7a4486353b92388 Mon Sep 17 00:00:00 2001 From: Jae-Seung Yeom Date: Wed, 7 Feb 2024 21:15:34 -0800 Subject: [PATCH 03/14] add boost package installation to CI --- .github/workflows/compile_test.yaml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/compile_test.yaml b/.github/workflows/compile_test.yaml index 20fcea2b..b44d0785 100644 --- a/.github/workflows/compile_test.yaml +++ b/.github/workflows/compile_test.yaml @@ -75,7 +75,8 @@ jobs: lz4 \ pkgconf \ libzmq5 \ - sqlite3 + sqlite3 \ + libboost-all-dev pip3 --version && python3 --version gcc --version sudo pip3 install jsonschema cffi ply pyyaml @@ -199,6 +200,11 @@ jobs: # externals: # - spec: "pkg-config@0.29.1" # prefix: /usr + boost: + buildable: False + externals: + - spec: "boost@1.83.0" + prefix: /usr gcc: externals: - spec: gcc@${GCC_VERSION} languages=c,c++ From 966833a883556c035fdf52a14cc1b7a69dd70829 Mon Sep 17 00:00:00 2001 From: Jae-Seung Yeom Date: Wed, 7 Feb 2024 22:06:04 -0800 Subject: [PATCH 04/14] add memstat utility functions --- src/dyad/utils/CMakeLists.txt | 22 +++++- src/dyad/utils/memstat.c | 136 ++++++++++++++++++++++++++++++++++ src/dyad/utils/memstat.h | 22 ++++++ 3 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 src/dyad/utils/memstat.c create mode 100644 src/dyad/utils/memstat.h diff --git a/src/dyad/utils/CMakeLists.txt b/src/dyad/utils/CMakeLists.txt index 86a1a50a..d70cd673 100644 --- a/src/dyad/utils/CMakeLists.txt +++ b/src/dyad/utils/CMakeLists.txt @@ -11,6 +11,10 @@ set(DYAD_MURMUR3_SRC ${CMAKE_CURRENT_SOURCE_DIR}/murmur3.c) set(DYAD_MURMUR3_PRIVATE_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/murmur3.h) set(DYAD_MURMUR3_PUBLIC_HEADERS) +set(DYAD_MEMSTAT_SRC ${CMAKE_CURRENT_SOURCE_DIR}/memstat.c) +set(DYAD_MEMSTAT_PRIVATE_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/memstat.h) +set(DYAD_MEMSTAT_PUBLIC_HEADERS) + add_library(${PROJECT_NAME}_utils SHARED ${DYAD_UTILS_SRC} ${DYAD_UTILS_PRIVATE_HEADERS} ${DYAD_UTILS_PUBLIC_HEADERS}) # set_target_properties(${PROJECT_NAME}_utils PROPERTIES CMAKE_INSTALL_RPATH @@ -51,10 +55,16 @@ if(DYAD_PROFILER STREQUAL "DFTRACER") target_link_libraries(test_cmp_canonical_path_prefix PRIVATE ${DTRACER_LIBRARIES}) endif() +add_library(${PROJECT_NAME}_memstat SHARED ${DYAD_MEMSTAT_SRC}) +target_compile_definitions(${PROJECT_NAME}_memstat PUBLIC DYAD_HAS_CONFIG) +#set_target_properties(${PROJECT_NAME}_memstat PROPERTIES CMAKE_INSTALL_RPATH +# "${DYAD_INSTALL_LIBDIR}") + dyad_add_werror_if_needed(${PROJECT_NAME}_utils) dyad_add_werror_if_needed(${PROJECT_NAME}_murmur3) dyad_add_werror_if_needed(test_murmur3) dyad_add_werror_if_needed(test_cmp_canonical_path_prefix) +dyad_add_werror_if_needed(${PROJECT_NAME}_memstat) install( TARGETS ${PROJECT_NAME}_utils @@ -74,5 +84,15 @@ install( RUNTIME DESTINATION ${DYAD_INSTALL_BINDIR} ) if(NOT "${DYAD_MURMUR3_PUBLIC_HEADERS}" STREQUAL "") - dyad_install_headers("${DYAD_UTILS_PUBLIC_HEADERS}" ${CMAKE_CURRENT_SOURCE_DIR}) + dyad_install_headers("${DYAD_MURMUR3_PUBLIC_HEADERS}" ${CMAKE_CURRENT_SOURCE_DIR}) +endif() +install( + TARGETS ${PROJECT_NAME}_memstat + EXPORT ${DYAD_EXPORTED_TARGETS} + LIBRARY DESTINATION ${DYAD_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${DYAD_INSTALL_LIBDIR} + RUNTIME DESTINATION ${DYAD_INSTALL_BINDIR} +) +if(NOT "${DYAD_MEMSTAT_PUBLIC_HEADERS}" STREQUAL "") + dyad_install_headers("${DYAD_MEMSTAT_PUBLIC_HEADERS}" ${CMAKE_CURRENT_SOURCE_DIR}) endif() diff --git a/src/dyad/utils/memstat.c b/src/dyad/utils/memstat.c new file mode 100644 index 00000000..759704bd --- /dev/null +++ b/src/dyad/utils/memstat.c @@ -0,0 +1,136 @@ +#if defined(DYAD_HAS_CONFIG) +#include +#else +#error "no config" +#endif + +#include +#include // getrusage () +#include // PATH_MAX +#include // sysconf(_SC_PAGESIZE) +#include +#include + +typedef struct { + unsigned long m_size, m_resident, m_share, m_text, m_lib, m_data, m_dt; +} statm_t; + +// https://docs.kernel.org/filesystems/proc.html +static int get_mem_status (statm_t* ms) +{ + unsigned long dummy; + const char* statm_path = "/proc/self/statm"; + + FILE *f = fopen (statm_path, "r"); + + if (!ms || !f) { + perror (statm_path); + return EXIT_FAILURE; + } + if (7 != fscanf (f, "%lu %lu %lu %lu %lu %lu %lu", + &(ms->m_size), &(ms->m_resident), &(ms->m_share), + &(ms->m_text), &(ms->m_lib), &(ms->m_data), &(ms->m_dt))) + { + perror (statm_path); + return EXIT_FAILURE; + } + fclose (f); + return EXIT_SUCCESS; +} + +int print_mem_status (const char* note, char* buf, unsigned bufsize) +{ + statm_t ms; + const char* nt = (!note ? "" : note); + if (get_mem_status (&ms) != EXIT_SUCCESS) return 0; + + if (!buf) { + printf ("%s:\tsize %lu\tresident %lu\tshare %lu\ttext %lu" + "\tlib %lu\tdata %lu\tdt %lu (in # pages of %ld)\n", + nt, ms.m_size, ms.m_resident, ms.m_share, ms.m_text, + ms.m_lib, ms.m_data, ms.m_dt, sysconf (_SC_PAGESIZE)); + } else { + return snprintf (buf, bufsize, "%s:\tsize %lu\tresident %lu\tshare %lu\t" + "text %lu\tlib %lu\tdata %lu\tdt %lu (in # pages of %ld)\n", + nt, ms.m_size, ms.m_resident, ms.m_share, ms.m_text, + ms.m_lib, ms.m_data, ms.m_dt, sysconf (_SC_PAGESIZE)); + } + return 0; +} + +// https://man7.org/linux/man-pages/man2/getrusage.2.html +int print_rusage (const char* note, char* buf, unsigned bufsize) +{ + struct rusage r_usage; + getrusage (RUSAGE_SELF,&r_usage); + + if (!buf) { + printf ("%s:\n" + "Memory usage: %ld kilobytes\n" + "page reclaims: %ld\n" + "page faults: %ld\n" + "block input ops: %ld\n" + "block input ops: %ld\n" + "voluntary context switches: %ld\n" + "involuntary context switches: %ld\n", + (!note ? "" : note), + r_usage.ru_maxrss, + r_usage.ru_minflt, + r_usage.ru_majflt, + r_usage.ru_inblock, + r_usage.ru_oublock, + r_usage.ru_nvcsw, + r_usage.ru_nivcsw); + } else { + int n = 0; + n = snprintf (buf, bufsize, "%s:\n" + "Memory usage: %ld kilobytes\n" + "page reclaims: %ld\n" + "page faults: %ld\n" + "block input ops: %ld\n" + "block input ops: %ld\n" + "voluntary context switches: %ld\n" + "involuntary context switches: %ld\n", + (!note ? "" : note), + r_usage.ru_maxrss, + r_usage.ru_minflt, + r_usage.ru_majflt, + r_usage.ru_inblock, + r_usage.ru_oublock, + r_usage.ru_nvcsw, + r_usage.ru_nivcsw); + return n; + } + return 0; +} + +int print_rusage_in_a_line (const char* note, char* buf, unsigned bufsize) +{ + struct rusage r_usage; + getrusage (RUSAGE_SELF, &r_usage); + + if (!buf) { + printf ("%s\tmemory usage: %ld %ld %ld %ld %ld %ld %ld\n", + (!note ? "" : note), + r_usage.ru_maxrss, + r_usage.ru_minflt, + r_usage.ru_majflt, + r_usage.ru_inblock, + r_usage.ru_oublock, + r_usage.ru_nvcsw, + r_usage.ru_nivcsw); + } else { + int n = 0; + n = snprintf (buf, bufsize, "%s\tmemory usage: %ld %ld %ld %ld %ld %ld %ld\n", + (!note ? "" : note), + r_usage.ru_maxrss, + r_usage.ru_minflt, + r_usage.ru_majflt, + r_usage.ru_inblock, + r_usage.ru_oublock, + r_usage.ru_nvcsw, + r_usage.ru_nivcsw); + return n; + } + return 0; +} diff --git a/src/dyad/utils/memstat.h b/src/dyad/utils/memstat.h new file mode 100644 index 00000000..19b8d030 --- /dev/null +++ b/src/dyad/utils/memstat.h @@ -0,0 +1,22 @@ +#ifndef DYAD_UTILS_MEMSTAT_H +#define DYAD_UTILS_MEMSTAT_H + +#if defined(DYAD_HAS_CONFIG) +#include +#else +#error "no config" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +int print_mem_status (const char* note, char* buf, unsigned bufsize); +int print_rusage (const char* note, char* buf, unsigned bufsize); +int print_rusage_in_a_line (const char* note, char* buf, unsigned bufsize); + +#ifdef __cplusplus +} +#endif + +#endif // DYAD_UTILS_MEMSTAT_H From c6cacc92d108e0b0f9d42c354463ebd10a515754 Mon Sep 17 00:00:00 2001 From: Jae-Seung Yeom Date: Sat, 10 Feb 2024 19:54:46 -0800 Subject: [PATCH 05/14] Add MRU --- src/dyad/residency/fcache.cpp | 40 +++++++- src/dyad/residency/fcache.hpp | 44 +++++++-- src/dyad/residency/fcache_impl.hpp | 4 +- src/dyad/residency/test_fcache.cpp | 147 ++++++++++++++++++++--------- 4 files changed, 178 insertions(+), 57 deletions(-) diff --git a/src/dyad/residency/fcache.cpp b/src/dyad/residency/fcache.cpp index 148b2aeb..338f0fd4 100644 --- a/src/dyad/residency/fcache.cpp +++ b/src/dyad/residency/fcache.cpp @@ -11,6 +11,7 @@ namespace dyad_residency { // Associative Cache Set //============================================================================= +// -------------------------- LRU ------------------------ bool Set_LRU::lookup (const std::string& fname, id_iterator_t &it) { id_idx_t& index_id = boost::multi_index::get (m_block_set); @@ -22,10 +23,12 @@ void Set_LRU::evict (void) { // LRU if (m_block_set.size () == 0) return; priority_idx_t& index_priority = boost::multi_index::get (m_block_set); - priority_iterator_t it = index_priority.begin (); - DYAD_LOG_INFO (NULL, " %s evicts %s from set %u\n", \ - m_level.c_str (), it->m_id.c_str (), m_id); - index_priority.erase (it); + if (!index_priority.empty ()) { + priority_iterator_t it = index_priority.begin (); + DYAD_LOG_INFO (NULL, " %s evicts %s from set %u\n", \ + m_level.c_str (), it->m_id.c_str (), m_id); + index_priority.erase (it); + } } void Set_LRU::load_and_access (const std::string& fname) @@ -91,8 +94,32 @@ std::ostream& operator<<(std::ostream& os, const Set_LRU & cc) return cc.print (os); } +// -------------------------- MRU ------------------------ +void Set_MRU::evict (void) +{ // MRU + if (m_block_set.size () == 0) return; + priority_idx_t& index_priority = boost::multi_index::get (m_block_set); + if (!index_priority.empty ()) { + auto it = index_priority.end (); --it; + DYAD_LOG_INFO (NULL, " %s evicts %s from set %u\n", \ + m_level.c_str (), it->m_id.c_str (), m_id); + index_priority.erase (it); + } +} +bool Set_MRU::access (const std::string& fname) +{ + return Set_LRU::access (fname); +} +std::ostream& operator<<(std::ostream& os, const Set_MRU & cc) +{ + return cc.print (os); +} + + + +// -------------------------- Prioritied ------------------------ bool Set_Prioritized::lookup (const std::string& fname, id_iterator_t &it) { id_idx_t& index_id = boost::multi_index::get (m_block_set); @@ -170,4 +197,9 @@ std::ostream& Set_Prioritized::print (std::ostream &os) const return os; } +std::ostream& operator<<(std::ostream& os, const Set_Prioritized& cc) +{ + return cc.print (os); +} + } // end of namespace dyad_residency diff --git a/src/dyad/residency/fcache.hpp b/src/dyad/residency/fcache.hpp index 4c71bb28..459c6ea7 100644 --- a/src/dyad/residency/fcache.hpp +++ b/src/dyad/residency/fcache.hpp @@ -119,6 +119,38 @@ class Set_LRU std::ostream& operator<<(std::ostream& os, const Set_LRU & sl); +class Set_MRU : public Set_LRU +{ + protected: + using Set_LRU::id; + using Set_LRU::priority; + using Set_LRU::LRU_Blocks; + using Set_LRU::id_idx_t; + using Set_LRU::id_iterator_t; + using Set_LRU::id_citerator_t; + using Set_LRU::priority_idx_t; + using Set_LRU::priority_iterator_t; + using Set_LRU::priority_citerator_t; + using Set_LRU::m_block_set; + + using Set_LRU::lookup; + using Set_LRU::access; + using Set_LRU::load_and_access; + using Set_LRU::get_priority; + + virtual void evict (void) override; + + public: + Set_MRU (unsigned int sz, unsigned int n_sets, unsigned int id) + : Set_LRU (sz, n_sets, id) {} + virtual ~Set_MRU () override {} + virtual bool access (const std::string& fname) override; + + using Set_LRU::print; +}; + +std::ostream& operator<<(std::ostream& os, const Set_MRU & sm); + class Set_Prioritized : public Set_LRU { @@ -152,17 +184,17 @@ class Set_Prioritized : public Set_LRU Prio_Blocks m_block_set; virtual bool lookup (const std::string& fname, id_iterator_t &it); - virtual void evict (void); + virtual void evict (void) override; virtual void access (id_iterator_t &it); - virtual void load_and_access (const std::string& fname); - virtual unsigned int get_priority (); + virtual void load_and_access (const std::string& fname) override; + virtual unsigned int get_priority () override; public: Set_Prioritized (unsigned int sz, unsigned int n_sets, unsigned int id) : Set_LRU (sz, n_sets, id) {} - virtual ~Set_Prioritized () {} - virtual bool access (const std::string& fname); - virtual std::ostream& print (std::ostream &os) const; + virtual ~Set_Prioritized () override {} + virtual bool access (const std::string& fname) override; + virtual std::ostream& print (std::ostream &os) const override; }; std::ostream& operator<<(std::ostream& os, const Set_Prioritized & sp); diff --git a/src/dyad/residency/fcache_impl.hpp b/src/dyad/residency/fcache_impl.hpp index 5c2bbf82..2bb9b9a9 100644 --- a/src/dyad/residency/fcache_impl.hpp +++ b/src/dyad/residency/fcache_impl.hpp @@ -76,8 +76,8 @@ template bool Cache::access (const std::string& fname) { //const unsigned int set_id = 0u; - //const unsigned int set_id = std::stoi (fname) % m_num_sets; - const unsigned int set_id = get_cache_set_id (fname); + const unsigned int set_id = std::stoi (fname) % m_num_sets; + //const unsigned int set_id = get_cache_set_id (fname); return m_set[set_id].access (fname); } diff --git a/src/dyad/residency/test_fcache.cpp b/src/dyad/residency/test_fcache.cpp index 249d3ca1..c3415928 100644 --- a/src/dyad/residency/test_fcache.cpp +++ b/src/dyad/residency/test_fcache.cpp @@ -2,79 +2,136 @@ #include #include #include +#include +#include -int main (int argc, char** argv) +namespace dyad_residency { - using namespace dyad_residency; - int seed = 0; +enum Set_Type {Set_LRU_, Set_MRU_, Set_Prio_, Set_End_}; + - if (argc > 2) { +template +using st = std::integral_constant; + +std::unique_ptr> make_cache(st, unsigned size, unsigned ways) { + return std::unique_ptr>(new Cache(size, ways)); +} +std::unique_ptr> make_cache(st, unsigned size, unsigned ways) { + return std::unique_ptr>(new Cache(size, ways)); +} +std::unique_ptr> make_cache(st, unsigned size, unsigned ways) { + return std::unique_ptr>(new Cache(size, ways)); +} + +template< template typename C, typename S> +int run_cache (int seed, + std::unique_ptr>& cacheL1, + std::unique_ptr>& cacheL2, + const std::vector& acc) +{ + bool hitL1 = false; + + if (!cacheL1 || !cacheL2) { + std::cerr << "Cannot allocate cache." << std::endl; return EXIT_FAILURE; } - if (argc == 2) { - seed = atoi (argv[1]); - } + cacheL1->set_seed (seed + 104677u); + cacheL1->set_level ("L1"); + cacheL2->set_seed (seed + 104681u); + cacheL2->set_level (" L2"); - typedef std::vector access; - access acc; // access pattern in terms of the block index - acc.push_back ("1"); - acc.push_back ("4"); - acc.push_back ("2"); - acc.push_back ("3"); - acc.push_back ("5"); - acc.push_back ("5"); - acc.push_back ("3"); - bool hitL1; - -#if 1 - Cache cacheL1 (4, 2); // 2-way set-associative - Cache cacheL2 (8, 2); // cache capacity = 8 blocks -#else - Cache cacheL1 (4, 0); // cache capacity = 4 blocks - Cache cacheL2 (8, 0); // fully-associative -#endif - cacheL1.set_seed (seed + 104677u); - cacheL1.set_level ("L1"); - cacheL2.set_seed (seed + 104681u); - cacheL2.set_level (" L2"); - - std::cout << "L1 Cache size set to " << cacheL1.size () << " blocks" << std::endl; - std::cout << "L2 Cache size set to " << cacheL2.size () << " blocks" << std::endl; + std::cout << "L1 Cache size set to " << cacheL1->size () << " blocks" << std::endl; + std::cout << "L2 Cache size set to " << cacheL2->size () << " blocks" << std::endl; std::cout << "accessing block 1, 4, 2, and 3 in order" << std::endl; - for (unsigned int i = 0; (i < cacheL1.size ()) && (i < acc.size ()); i++) { - hitL1 = cacheL1.access (acc[i]); - if (!hitL1) cacheL2.access (acc[i]); + for (unsigned int i = 0; (i < cacheL1->size ()) && (i < acc.size ()); i++) { + hitL1 = cacheL1->access (acc[i]); + if (!hitL1) cacheL2->access (acc[i]); } std::cout << "-------------------------L1----------------------------" << std::endl; - std::cout << cacheL1 << std::endl; + std::cout << *cacheL1 << std::endl; std::cout << "-------------------------L2----------------------------" << std::endl; - std::cout << cacheL2 << std::endl; + std::cout << *cacheL2 << std::endl; std::cout << "-------------------------------------------------------" << std::endl; std::cout << "accessing block 5" << std::endl; - hitL1 = cacheL1.access (acc[4]); - if (!hitL1) cacheL2.access (acc[4]); + hitL1 = cacheL1->access (acc[4]); + if (!hitL1) cacheL2->access (acc[4]); std::cout << "-------------------------L1----------------------------" << std::endl; - std::cout << cacheL1 << std::endl; + std::cout << *cacheL1 << std::endl; std::cout << "-------------------------L2----------------------------" << std::endl; - std::cout << cacheL2 << std::endl; + std::cout << *cacheL2 << std::endl; std::cout << "-------------------------------------------------------" << std::endl; std::cout << "accessing block 1, 4, 2, 3, 5, 5, and 3 in order" << std::endl; for (unsigned int i = 0; i < acc.size (); i++) { - hitL1 = cacheL1.access (acc[i]); - if (!hitL1) cacheL2.access (acc[i]); + hitL1 = cacheL1->access (acc[i]); + if (!hitL1) cacheL2->access (acc[i]); } std::cout << "-------------------------L1----------------------------" << std::endl; - std::cout << cacheL1 << std::endl; + std::cout << *cacheL1 << std::endl; std::cout << "-------------------------L2----------------------------" << std::endl; - std::cout << cacheL2 << std::endl; + std::cout << *cacheL2 << std::endl; std::cout << "-------------------------------------------------------" << std::endl; return EXIT_SUCCESS; } + +int cache_demo (const Set_Type st, int seed, + unsigned sizeL1, unsigned waysL1, + unsigned sizeL2, unsigned waysL2, + const std::vector& acc) +{ + if (st == Set_LRU_) { + auto cacheL1 = std::unique_ptr>(new Cache (sizeL1, waysL1)); + auto cacheL2 = std::unique_ptr>(new Cache (sizeL2, waysL2)); + return run_cache (seed, cacheL1, cacheL2, acc); + } else if (st == Set_MRU_) { + auto cacheL1 = std::unique_ptr>(new Cache (sizeL1, waysL1)); + auto cacheL2 = std::unique_ptr>(new Cache (sizeL2, waysL2)); + return run_cache (seed, cacheL1, cacheL2, acc); + } else if (st == Set_Prio_) { + auto cacheL1 = std::unique_ptr>(new Cache (sizeL1, waysL1)); + auto cacheL2 = std::unique_ptr>(new Cache (sizeL2, waysL2)); + return run_cache (seed, cacheL1, cacheL2, acc); + } + return EXIT_FAILURE; +} + +} // end of namespace dyad_Residency + + +int main (int argc, char** argv) +{ + using namespace dyad_residency; + + int seed = 0; + Set_Type set_type = Set_LRU_; + + if (argc > 3) { + return EXIT_FAILURE; + } + if (argc >= 2) { + seed = atoi (argv[1]); + } + if (argc == 3) { + int st = atoi (argv[2]); + set_type = static_cast (st % Set_End_); + } + + typedef std::vector access; + access acc; // access pattern in terms of the block index + acc.push_back ("1"); + acc.push_back ("4"); + acc.push_back ("2"); + acc.push_back ("3"); + acc.push_back ("5"); + acc.push_back ("5"); + acc.push_back ("3"); + + return cache_demo (set_type, seed, 4, 2, 8, 2, acc); +} From 71883ad00d5bc11ddc01f56be6f2379a31c8a808 Mon Sep 17 00:00:00 2001 From: Jae-Seung Yeom Date: Wed, 18 Jun 2025 09:55:42 -0700 Subject: [PATCH 06/14] Applied clang-format --- src/dyad/residency/fcache.cpp | 97 +++++----- src/dyad/residency/fcache.hpp | 279 +++++++++++++++++------------ src/dyad/residency/fcache_impl.hpp | 27 ++- src/dyad/residency/test_fcache.cpp | 63 ++++--- 4 files changed, 269 insertions(+), 197 deletions(-) diff --git a/src/dyad/residency/fcache.cpp b/src/dyad/residency/fcache.cpp index 338f0fd4..e8945497 100644 --- a/src/dyad/residency/fcache.cpp +++ b/src/dyad/residency/fcache.cpp @@ -1,18 +1,18 @@ -#include #include +#include #define DYAD_UTIL_LOGGER #include - -namespace dyad_residency { +namespace dyad_residency +{ //============================================================================= // Associative Cache Set //============================================================================= // -------------------------- LRU ------------------------ -bool Set_LRU::lookup (const std::string& fname, id_iterator_t &it) +bool Set_LRU::lookup (const std::string& fname, id_iterator_t& it) { id_idx_t& index_id = boost::multi_index::get (m_block_set); it = index_id.find (fname); @@ -20,13 +20,17 @@ bool Set_LRU::lookup (const std::string& fname, id_iterator_t &it) } void Set_LRU::evict (void) -{ // LRU - if (m_block_set.size () == 0) return; +{ // LRU + if (m_block_set.size () == 0) + return; priority_idx_t& index_priority = boost::multi_index::get (m_block_set); if (!index_priority.empty ()) { priority_iterator_t it = index_priority.begin (); - DYAD_LOG_INFO (NULL, " %s evicts %s from set %u\n", \ - m_level.c_str (), it->m_id.c_str (), m_id); + DYAD_LOG_INFO (NULL, + " %s evicts %s from set %u\n", + m_level.c_str (), + it->m_id.c_str (), + m_id); index_priority.erase (it); } } @@ -35,8 +39,7 @@ void Set_LRU::load_and_access (const std::string& fname) { m_num_miss++; - DYAD_LOG_INFO (NULL, " %s adds %s to set %u\n", \ - m_level.c_str (), fname.c_str (), m_id); + DYAD_LOG_INFO (NULL, " %s adds %s to set %u\n", m_level.c_str (), fname.c_str (), m_id); if (m_size == m_block_set.size ()) { evict (); } @@ -45,7 +48,7 @@ void Set_LRU::load_and_access (const std::string& fname) m_seqno++; } -void Set_LRU::access (id_iterator_t &it) +void Set_LRU::access (id_iterator_t& it) { Simple_Block blk = *it; m_block_set.erase (it); @@ -56,12 +59,15 @@ void Set_LRU::access (id_iterator_t &it) bool Set_LRU::access (const std::string& fname) { id_iterator_t it; - if (lookup (fname, it)) { // hit - DYAD_LOG_INFO (NULL, " %s reuses %s from set %u\n", \ - m_level.c_str (), fname.c_str (), m_id); + if (lookup (fname, it)) { // hit + DYAD_LOG_INFO (NULL, + " %s reuses %s from set %u\n", + m_level.c_str (), + fname.c_str (), + m_id); access (it); return true; - } else { // miss + } else { // miss load_and_access (fname); return false; } @@ -72,10 +78,10 @@ unsigned int Set_LRU::get_priority () return m_seqno; } -std::ostream& Set_LRU::print (std::ostream &os) const +std::ostream& Set_LRU::print (std::ostream& os) const { os << "size : " << m_size << std::endl; - os << "num accesses : " << m_seqno<< std::endl; + os << "num accesses : " << m_seqno << std::endl; os << "num misses : " << m_num_miss << std::endl; os << "blkId : " << std::endl; @@ -89,20 +95,25 @@ std::ostream& Set_LRU::print (std::ostream &os) const return os; } -std::ostream& operator<<(std::ostream& os, const Set_LRU & cc) +std::ostream& operator<< (std::ostream& os, const Set_LRU& cc) { return cc.print (os); } // -------------------------- MRU ------------------------ void Set_MRU::evict (void) -{ // MRU - if (m_block_set.size () == 0) return; +{ // MRU + if (m_block_set.size () == 0) + return; priority_idx_t& index_priority = boost::multi_index::get (m_block_set); if (!index_priority.empty ()) { - auto it = index_priority.end (); --it; - DYAD_LOG_INFO (NULL, " %s evicts %s from set %u\n", \ - m_level.c_str (), it->m_id.c_str (), m_id); + auto it = index_priority.end (); + --it; + DYAD_LOG_INFO (NULL, + " %s evicts %s from set %u\n", + m_level.c_str (), + it->m_id.c_str (), + m_id); index_priority.erase (it); } } @@ -112,15 +123,13 @@ bool Set_MRU::access (const std::string& fname) return Set_LRU::access (fname); } -std::ostream& operator<<(std::ostream& os, const Set_MRU & cc) +std::ostream& operator<< (std::ostream& os, const Set_MRU& cc) { return cc.print (os); } - - // -------------------------- Prioritied ------------------------ -bool Set_Prioritized::lookup (const std::string& fname, id_iterator_t &it) +bool Set_Prioritized::lookup (const std::string& fname, id_iterator_t& it) { id_idx_t& index_id = boost::multi_index::get (m_block_set); it = index_id.find (fname); @@ -129,11 +138,15 @@ bool Set_Prioritized::lookup (const std::string& fname, id_iterator_t &it) void Set_Prioritized::evict (void) { - if (m_block_set.size () == 0) return; + if (m_block_set.size () == 0) + return; priority_idx_t& index_priority = boost::multi_index::get (m_block_set); priority_iterator_t it = index_priority.begin (); - DYAD_LOG_INFO (NULL, " %s evicts %s from set %u\n", \ - m_level.c_str (), it->m_id.c_str (), m_id); + DYAD_LOG_INFO (NULL, + " %s evicts %s from set %u\n", + m_level.c_str (), + it->m_id.c_str (), + m_id); index_priority.erase (it); } @@ -141,8 +154,7 @@ void Set_Prioritized::load_and_access (const std::string& fname) { m_num_miss++; - DYAD_LOG_INFO (NULL, " %s adds %s to set %u\n", \ - m_level.c_str (), fname.c_str (), m_id); + DYAD_LOG_INFO (NULL, " %s adds %s to set %u\n", m_level.c_str (), fname.c_str (), m_id); if (m_size == m_block_set.size ()) { evict (); } @@ -151,7 +163,7 @@ void Set_Prioritized::load_and_access (const std::string& fname) m_seqno++; } -void Set_Prioritized::access (id_iterator_t &it) +void Set_Prioritized::access (id_iterator_t& it) { Ranked_Block blk = *it; // reassigning the priority @@ -164,12 +176,15 @@ void Set_Prioritized::access (id_iterator_t &it) bool Set_Prioritized::access (const std::string& fname) { id_iterator_t it; - if (lookup (fname, it)) { // hit - DYAD_LOG_INFO (NULL, " %s reuses %s from set %u\n", \ - m_level.c_str (), fname.c_str (), m_id); + if (lookup (fname, it)) { // hit + DYAD_LOG_INFO (NULL, + " %s reuses %s from set %u\n", + m_level.c_str (), + fname.c_str (), + m_id); access (it); return true; - } else { // miss + } else { // miss load_and_access (fname); return false; } @@ -180,10 +195,10 @@ unsigned int Set_Prioritized::get_priority () return m_seqno; } -std::ostream& Set_Prioritized::print (std::ostream &os) const +std::ostream& Set_Prioritized::print (std::ostream& os) const { os << "size : " << m_size << std::endl; - os << "num accesses : " << m_seqno<< std::endl; + os << "num accesses : " << m_seqno << std::endl; os << "num misses : " << m_num_miss << std::endl; os << "priority blkId:" << std::endl; @@ -197,9 +212,9 @@ std::ostream& Set_Prioritized::print (std::ostream &os) const return os; } -std::ostream& operator<<(std::ostream& os, const Set_Prioritized& cc) +std::ostream& operator<< (std::ostream& os, const Set_Prioritized& cc) { return cc.print (os); } -} // end of namespace dyad_residency +} // end of namespace dyad_residency diff --git a/src/dyad/residency/fcache.hpp b/src/dyad/residency/fcache.hpp index 459c6ea7..7a1e6a8c 100644 --- a/src/dyad/residency/fcache.hpp +++ b/src/dyad/residency/fcache.hpp @@ -7,69 +7,71 @@ #error "no config" #endif -#include -#include #include +#include #include #include +#include -#include -#include #include +#include #include +#include - -namespace dyad_residency { +namespace dyad_residency +{ //============================================================================= // Cache Block (cache line) for LRU //============================================================================= -struct Simple_Block -{ - std::string m_id; // unique id, file name +struct Simple_Block { + std::string m_id; // unique id, file name - Simple_Block (const std::string& id) - : m_id (id) {} + Simple_Block (const std::string& id) : m_id (id) + { + } }; -struct Ranked_Block -{ - std::string m_id; // unique id, file name - unsigned int m_priority; // priority +struct Ranked_Block { + std::string m_id; // unique id, file name + unsigned int m_priority; // priority - Ranked_Block (const std::string& id, unsigned int priority) - : m_id (id), m_priority (priority) {} + Ranked_Block (const std::string& id, unsigned int priority) : m_id (id), m_priority (priority) + { + } }; - //============================================================================= // Associative Cache Set //============================================================================= class Set_LRU { - protected: - struct id{}; - struct priority{}; + protected: + struct id { + }; + struct priority { + }; typedef boost::multi_index_container< Simple_Block, boost::multi_index::indexed_by< - boost::multi_index::hashed_unique, - BOOST_MULTI_INDEX_MEMBER(Simple_Block, std::string, m_id)>, - boost::multi_index::sequenced > - > - > LRU_Blocks; - - typedef boost::multi_index::index::type id_idx_t; - typedef boost::multi_index::index::type::iterator id_iterator_t; - typedef boost::multi_index::index::type::const_iterator id_citerator_t; - - typedef boost::multi_index::index::type priority_idx_t; - typedef boost::multi_index::index::type::iterator priority_iterator_t; - typedef boost::multi_index::index::type::const_iterator priority_citerator_t; - - protected: + boost::multi_index::hashed_unique< + boost::multi_index::tag, + BOOST_MULTI_INDEX_MEMBER (Simple_Block, std::string, m_id)>, + boost::multi_index::sequenced > > > + LRU_Blocks; + + typedef boost::multi_index::index::type id_idx_t; + typedef boost::multi_index::index::type::iterator id_iterator_t; + typedef boost::multi_index::index::type::const_iterator id_citerator_t; + + typedef boost::multi_index::index::type priority_idx_t; + typedef boost::multi_index::index::type::iterator priority_iterator_t; + typedef boost::multi_index::index::type::const_iterator + priority_citerator_t; + + protected: /** Cache set capacity (n-way in a set associative cache) in terms of the * maximum number of blocks */ unsigned int m_size; @@ -78,7 +80,6 @@ class Set_LRU /// Id of this set unsigned int m_id; - /** Current access sequence number. This can be used to calculate the numbeer * of accesses */ unsigned int m_seqno; @@ -91,113 +92,145 @@ class Set_LRU LRU_Blocks m_block_set; - virtual bool lookup (const std::string& fname, id_iterator_t &it); + virtual bool lookup (const std::string& fname, id_iterator_t& it); virtual void evict (void); - virtual void access (id_iterator_t &it); + virtual void access (id_iterator_t& it); virtual void load_and_access (const std::string& fname); virtual unsigned int get_priority (); - public: - Set_LRU(unsigned int sz, unsigned int n_sets, unsigned int id) - : m_size (sz), m_num_sets (n_sets), m_id (id), - m_seqno (0u), m_seqno0 (0u), m_num_miss (0u) {} - virtual ~Set_LRU () {} - - unsigned int size (void) const { return m_size; } - unsigned int get_num_access (void) const { return m_seqno - m_seqno0; } - unsigned int get_num_miss (void) const { return m_num_miss; } - void reset_cnts (void) { m_seqno0 = m_seqno; m_num_miss = 0u; } - std::string get_level (void) const { return m_level; } - void set_level (const std::string& level) { m_level = level; } + public: + Set_LRU (unsigned int sz, unsigned int n_sets, unsigned int id) + : m_size (sz), m_num_sets (n_sets), m_id (id), m_seqno (0u), m_seqno0 (0u), m_num_miss (0u) + { + } + virtual ~Set_LRU () + { + } + + unsigned int size (void) const + { + return m_size; + } + unsigned int get_num_access (void) const + { + return m_seqno - m_seqno0; + } + unsigned int get_num_miss (void) const + { + return m_num_miss; + } + void reset_cnts (void) + { + m_seqno0 = m_seqno; + m_num_miss = 0u; + } + std::string get_level (void) const + { + return m_level; + } + void set_level (const std::string& level) + { + m_level = level; + } /** Access by a block index, and returns true if hit. Otherwise false. * And there must be a following access at the lower cache layer. */ virtual bool access (const std::string& fname); - virtual std::ostream& print (std::ostream &os) const; + virtual std::ostream& print (std::ostream& os) const; }; -std::ostream& operator<<(std::ostream& os, const Set_LRU & sl); +std::ostream& operator<< (std::ostream& os, const Set_LRU& sl); class Set_MRU : public Set_LRU { - protected: + protected: using Set_LRU::id; - using Set_LRU::priority; - using Set_LRU::LRU_Blocks; + using Set_LRU::id_citerator_t; using Set_LRU::id_idx_t; using Set_LRU::id_iterator_t; - using Set_LRU::id_citerator_t; + using Set_LRU::LRU_Blocks; + using Set_LRU::m_block_set; + using Set_LRU::priority; + using Set_LRU::priority_citerator_t; using Set_LRU::priority_idx_t; using Set_LRU::priority_iterator_t; - using Set_LRU::priority_citerator_t; - using Set_LRU::m_block_set; - using Set_LRU::lookup; using Set_LRU::access; - using Set_LRU::load_and_access; using Set_LRU::get_priority; + using Set_LRU::load_and_access; + using Set_LRU::lookup; virtual void evict (void) override; - public: - Set_MRU (unsigned int sz, unsigned int n_sets, unsigned int id) - : Set_LRU (sz, n_sets, id) {} - virtual ~Set_MRU () override {} + public: + Set_MRU (unsigned int sz, unsigned int n_sets, unsigned int id) : Set_LRU (sz, n_sets, id) + { + } + virtual ~Set_MRU () override + { + } virtual bool access (const std::string& fname) override; using Set_LRU::print; }; -std::ostream& operator<<(std::ostream& os, const Set_MRU & sm); - +std::ostream& operator<< (std::ostream& os, const Set_MRU& sm); class Set_Prioritized : public Set_LRU { - protected: - struct id{}; - struct priority{}; + protected: + struct id { + }; + struct priority { + }; typedef boost::multi_index_container< Ranked_Block, boost::multi_index::indexed_by< - boost::multi_index::hashed_unique, - BOOST_MULTI_INDEX_MEMBER(Ranked_Block, std::string, m_id)>, - boost::multi_index::ordered_non_unique, - BOOST_MULTI_INDEX_MEMBER(Ranked_Block, unsigned int, m_priority)> - > - > Prio_Blocks; - - typedef boost::multi_index::index::type id_idx_t; - typedef boost::multi_index::index::type::iterator id_iterator_t; - typedef boost::multi_index::index::type::const_iterator id_citerator_t; - - typedef boost::multi_index::index::type priority_idx_t; - typedef boost::multi_index::index::type::iterator priority_iterator_t; - typedef boost::multi_index::index::type::const_iterator priority_citerator_t; - - private: - using Set_LRU::lookup; + boost::multi_index::hashed_unique< + boost::multi_index::tag, + BOOST_MULTI_INDEX_MEMBER (Ranked_Block, std::string, m_id)>, + boost::multi_index::ordered_non_unique< + boost::multi_index::tag, + BOOST_MULTI_INDEX_MEMBER (Ranked_Block, unsigned int, m_priority)> > > + Prio_Blocks; + + typedef boost::multi_index::index::type id_idx_t; + typedef boost::multi_index::index::type::iterator id_iterator_t; + typedef boost::multi_index::index::type::const_iterator id_citerator_t; + + typedef boost::multi_index::index::type priority_idx_t; + typedef boost::multi_index::index::type::iterator priority_iterator_t; + typedef boost::multi_index::index::type::const_iterator + priority_citerator_t; + + private: using Set_LRU::access; + using Set_LRU::lookup; - protected: + protected: Prio_Blocks m_block_set; - virtual bool lookup (const std::string& fname, id_iterator_t &it); + virtual bool lookup (const std::string& fname, id_iterator_t& it); virtual void evict (void) override; - virtual void access (id_iterator_t &it); + virtual void access (id_iterator_t& it); virtual void load_and_access (const std::string& fname) override; virtual unsigned int get_priority () override; - public: + public: Set_Prioritized (unsigned int sz, unsigned int n_sets, unsigned int id) - : Set_LRU (sz, n_sets, id) {} - virtual ~Set_Prioritized () override {} + : Set_LRU (sz, n_sets, id) + { + } + virtual ~Set_Prioritized () override + { + } virtual bool access (const std::string& fname) override; - virtual std::ostream& print (std::ostream &os) const override; + virtual std::ostream& print (std::ostream& os) const override; }; -std::ostream& operator<<(std::ostream& os, const Set_Prioritized & sp); +std::ostream& operator<< (std::ostream& os, const Set_Prioritized& sp); //============================================================================= // Set Associative Cache @@ -207,47 +240,63 @@ std::ostream& operator<<(std::ostream& os, const Set_Prioritized & sp); template class Cache { - public: + public: using Sets = typename std::vector; - protected: - unsigned int m_size; ///< Capacity of cache in terms of the number of blocks - unsigned int m_ways; ///< For x-way set-associativity - unsigned int m_num_sets; ///< Number of sets - unsigned int m_seed; ///< Seed used to compute hash in determining cache set - std::string m_level; ///< Level of this cache. e,g., L2. + protected: + unsigned int m_size; ///< Capacity of cache in terms of the number of blocks + unsigned int m_ways; ///< For x-way set-associativity + unsigned int m_num_sets; ///< Number of sets + unsigned int m_seed; ///< Seed used to compute hash in determining cache set + std::string m_level; ///< Level of this cache. e,g., L2. Sets m_set; unsigned int get_cache_set_id (const std::string& fname) const; - public: + public: Cache (unsigned int sz, unsigned int w); - virtual ~Cache () {} - - unsigned int size (void) const { return m_size; } - unsigned int get_num_ways (void) const { return m_ways; } - unsigned int get_num_sets (void) const { return m_num_sets; } + virtual ~Cache () + { + } + + unsigned int size (void) const + { + return m_size; + } + unsigned int get_num_ways (void) const + { + return m_ways; + } + unsigned int get_num_sets (void) const + { + return m_num_sets; + } unsigned int get_num_access (void) const; unsigned int get_num_miss (void) const; void reset_cnts (void); - void set_seed (unsigned int seed) { m_seed = seed; } - std::string get_level (void) const { return m_level; } + void set_seed (unsigned int seed) + { + m_seed = seed; + } + std::string get_level (void) const + { + return m_level; + } void set_level (const std::string& level); /// Returns true if hit. Otherwise false. virtual bool access (const std::string& fname); - std::ostream& print (std::ostream &os) const; + std::ostream& print (std::ostream& os) const; }; template -std::ostream& operator<< (std::ostream& os, const Cache & cc); - +std::ostream& operator<< (std::ostream& os, const Cache& cc); -} // end of namespace dyad_residency +} // end of namespace dyad_residency #include -#endif // DYAD_RESIDENCY_FCACHE_H +#endif // DYAD_RESIDENCY_FCACHE_H diff --git a/src/dyad/residency/fcache_impl.hpp b/src/dyad/residency/fcache_impl.hpp index 2bb9b9a9..41c11ac1 100644 --- a/src/dyad/residency/fcache_impl.hpp +++ b/src/dyad/residency/fcache_impl.hpp @@ -1,20 +1,19 @@ #ifndef DYAD_RESIDENCY_FCACHE_IMPL_H #define DYAD_RESIDENCY_FCACHE_IMPL_H -#include #include +#include - -namespace dyad_residency { +namespace dyad_residency +{ //============================================================================= // Cache //============================================================================= template -Cache::Cache (unsigned int sz, unsigned int w) -: m_size (sz), m_ways (w), m_seed (104729u) +Cache::Cache (unsigned int sz, unsigned int w) : m_size (sz), m_ways (w), m_seed (104729u) { - if (m_ways == 0) { // fully associative + if (m_ways == 0) { // fully associative m_num_sets = 1; m_ways = m_size; } else { @@ -69,15 +68,15 @@ unsigned int Cache::get_cache_set_id (const std::string& fname) const const char* str = fname.c_str (); MurmurHash3_x64_128 (str, strlen (str), m_seed, hash); - return (hash[0] ^ hash[1] ^ hash[2] ^ hash[3]) % m_num_sets; + return (hash[0] ^ hash[1] ^ hash[2] ^ hash[3]) % m_num_sets; } template bool Cache::access (const std::string& fname) { - //const unsigned int set_id = 0u; + // const unsigned int set_id = 0u; const unsigned int set_id = std::stoi (fname) % m_num_sets; - //const unsigned int set_id = get_cache_set_id (fname); + // const unsigned int set_id = get_cache_set_id (fname); return m_set[set_id].access (fname); } @@ -92,7 +91,7 @@ void Cache::set_level (const std::string& level) } template -std::ostream& Cache::print (std::ostream &os) const +std::ostream& Cache::print (std::ostream& os) const { os << "==========================================" << std::endl; os << "size: " << m_size << std::endl; @@ -102,7 +101,7 @@ std::ostream& Cache::print (std::ostream &os) const typename Sets::const_iterator it = m_set.begin (); typename Sets::const_iterator itend = m_set.end (); for (unsigned int i = 0; it != itend; it++, i++) { - os << "-------- set "<< i << " ----------" << std::endl; + os << "-------- set " << i << " ----------" << std::endl; os << *it << std::endl; } os << "==========================================" << std::endl; @@ -110,10 +109,10 @@ std::ostream& Cache::print (std::ostream &os) const } template -std::ostream& operator<< (std::ostream& os, const Cache & cc) +std::ostream& operator<< (std::ostream& os, const Cache& cc) { return cc.print (os); } -} // end of namespace dyad_residency -#endif // DYAD_RESIDENCY_FCACHE_IMPL_H +} // end of namespace dyad_residency +#endif // DYAD_RESIDENCY_FCACHE_IMPL_H diff --git a/src/dyad/residency/test_fcache.cpp b/src/dyad/residency/test_fcache.cpp index c3415928..f23fcf03 100644 --- a/src/dyad/residency/test_fcache.cpp +++ b/src/dyad/residency/test_fcache.cpp @@ -1,30 +1,32 @@ +#include #include -#include #include -#include #include +#include #include namespace dyad_residency { -enum Set_Type {Set_LRU_, Set_MRU_, Set_Prio_, Set_End_}; - +enum Set_Type { Set_LRU_, Set_MRU_, Set_Prio_, Set_End_ }; -template +template using st = std::integral_constant; -std::unique_ptr> make_cache(st, unsigned size, unsigned ways) { - return std::unique_ptr>(new Cache(size, ways)); +std::unique_ptr> make_cache (st, unsigned size, unsigned ways) +{ + return std::unique_ptr> (new Cache (size, ways)); } -std::unique_ptr> make_cache(st, unsigned size, unsigned ways) { - return std::unique_ptr>(new Cache(size, ways)); +std::unique_ptr> make_cache (st, unsigned size, unsigned ways) +{ + return std::unique_ptr> (new Cache (size, ways)); } -std::unique_ptr> make_cache(st, unsigned size, unsigned ways) { - return std::unique_ptr>(new Cache(size, ways)); +std::unique_ptr> make_cache (st, unsigned size, unsigned ways) +{ + return std::unique_ptr> (new Cache (size, ways)); } -template< template typename C, typename S> +template