From b8b960298a9366d1a9bab268384841f5669b2513 Mon Sep 17 00:00:00 2001 From: Jae-Seung Yeom Date: Tue, 6 Feb 2024 15:27:33 -0800 Subject: [PATCH 1/5] 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 fe73effa..a050973e 100644 --- a/src/dyad/CMakeLists.txt +++ b/src/dyad/CMakeLists.txt @@ -6,4 +6,5 @@ add_subdirectory(core) add_subdirectory(modules) add_subdirectory(wrapper) add_subdirectory(stream) +add_subdirectory(residency) From 9ee0cc8db6d93e7a0b8f60f68c5a94e25077cb38 Mon Sep 17 00:00:00 2001 From: Jae-Seung Yeom Date: Tue, 6 Feb 2024 21:10:50 -0800 Subject: [PATCH 2/5] 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 c3610a3b..4b2d114a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -285,6 +285,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}) + #----------------------------------------------------------------------------- # Configure the config.cmake file for the build directory 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 56a62fadace27f2ac2100973f3eb781a6f837bae Mon Sep 17 00:00:00 2001 From: Jae-Seung Yeom Date: Wed, 7 Feb 2024 21:15:34 -0800 Subject: [PATCH 3/5] 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 ff77aac3..21fae466 100644 --- a/.github/workflows/compile_test.yaml +++ b/.github/workflows/compile_test.yaml @@ -65,7 +65,8 @@ jobs: lz4 \ pkgconf \ libzmq5 \ - sqlite + sqlite \ + libboost-all-dev sudo pip install jsonschema cffi ply pyyaml sudo chmod 777 /usr -R - name: Install Spack @@ -195,6 +196,11 @@ jobs: externals: - spec: "pkg-config@0.29.1" prefix: /usr + boost: + buildable: False + externals: + - spec: "boost@1.71.0" + prefix: /usr gcc: externals: - spec: gcc@${GCC_VERSION} languages=c,c++ From 278fda0d5b8403380337e022a444438ae14488ec Mon Sep 17 00:00:00 2001 From: Jae-Seung Yeom Date: Wed, 7 Feb 2024 22:06:04 -0800 Subject: [PATCH 4/5] add memstat utility functions --- src/dyad/utils/CMakeLists.txt | 21 +++++- src/dyad/utils/memstat.c | 136 ++++++++++++++++++++++++++++++++++ src/dyad/utils/memstat.h | 22 ++++++ 3 files changed, 178 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 f3f958ee..e4c60ba4 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 @@ -32,6 +36,7 @@ target_include_directories(${PROJECT_NAME}_utils PUBLIC $) add_library(${PROJECT_NAME}_murmur3 SHARED ${DYAD_MURMUR3_SRC}) +target_compile_definitions(${PROJECT_NAME}_murmur3 PUBLIC DYAD_HAS_CONFIG) set_target_properties(${PROJECT_NAME}_murmur3 PROPERTIES CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${DYAD_LIBDIR}") @@ -51,6 +56,10 @@ if(DYAD_PROFILER STREQUAL "DLIO_PROFILER") target_link_libraries(test_cmp_canonical_path_prefix PRIVATE ${DLIO_PROFILER_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 + "${CMAKE_INSTALL_PREFIX}/${DYAD_LIBDIR}") if (TARGET DYAD_C_FLAGS_werror) target_link_libraries(${PROJECT_NAME}_utils PRIVATE DYAD_C_FLAGS_werror) @@ -77,5 +86,15 @@ install( RUNTIME DESTINATION ${DYAD_INSTALL_BIN_DIR} ) 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_LIB_DIR} + ARCHIVE DESTINATION ${DYAD_INSTALL_LIB_DIR} + RUNTIME DESTINATION ${DYAD_INSTALL_BIN_DIR} +) +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 45b22c45cb3f914efa0a72e9e88d921baa5da88a Mon Sep 17 00:00:00 2001 From: Jae-Seung Yeom Date: Tue, 20 Feb 2024 12:14:51 -0800 Subject: [PATCH 5/5] template types for id of cache block and priority --- src/dyad/residency/fcache.cpp | 139 +++++++++++++++++++++++------ src/dyad/residency/fcache.hpp | 116 +++++++++++++++--------- src/dyad/residency/fcache_impl.hpp | 38 ++++---- src/dyad/residency/test_fcache.cpp | 13 +-- 4 files changed, 217 insertions(+), 89 deletions(-) diff --git a/src/dyad/residency/fcache.cpp b/src/dyad/residency/fcache.cpp index 148b2aeb..a98d230f 100644 --- a/src/dyad/residency/fcache.cpp +++ b/src/dyad/residency/fcache.cpp @@ -1,5 +1,7 @@ #include #include +#include +#include #define DYAD_UTIL_LOGGER #include @@ -7,55 +9,73 @@ namespace dyad_residency { +std::string id_str (const std::string& id) +{ + return id; +} + +template +std::string id_str (const T& id) +{ + using namespace std; + return to_string (id); +} + + //============================================================================= // Associative Cache Set //============================================================================= -bool Set_LRU::lookup (const std::string& fname, id_iterator_t &it) +template +bool Set_LRU::lookup (const IDT& 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) +template +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); + m_level.c_str (), id_str (it->m_id).c_str (), m_id); index_priority.erase (it); } -void Set_LRU::load_and_access (const std::string& fname) +template +void Set_LRU::load_and_access (const IDT& fname) { m_num_miss++; DYAD_LOG_INFO (NULL, " %s adds %s to set %u\n", \ - m_level.c_str (), fname.c_str (), m_id); + m_level.c_str (), id_str (fname).c_str (), m_id); if (m_size == m_block_set.size ()) { evict (); } - m_block_set.insert (Simple_Block (fname)); + m_block_set.insert (Simple_Block (fname)); m_seqno++; } -void Set_LRU::access (id_iterator_t &it) +template +void Set_LRU::access (id_iterator_t &it) { - Simple_Block blk = *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) +template +bool Set_LRU::access (const IDT& 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); + m_level.c_str (), id_str (fname).c_str (), m_id); access (it); return true; } else { // miss @@ -64,12 +84,14 @@ bool Set_LRU::access (const std::string& fname) } } -unsigned int Set_LRU::get_priority () +template +unsigned int Set_LRU::get_priority (unsigned int) { return m_seqno; } -std::ostream& Set_LRU::print (std::ostream &os) const +template +std::ostream& Set_LRU::print (std::ostream &os) const { os << "size : " << m_size << std::endl; os << "num accesses : " << m_seqno<< std::endl; @@ -86,60 +108,66 @@ std::ostream& Set_LRU::print (std::ostream &os) const return os; } -std::ostream& operator<<(std::ostream& os, const Set_LRU & cc) +template +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) +template +bool Set_Prioritized::lookup (const IDT& 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) +template +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); + m_level.c_str (), id_str (it->m_id).c_str (), m_id); index_priority.erase (it); } -void Set_Prioritized::load_and_access (const std::string& fname) +template +void Set_Prioritized::load_and_access (const IDT& fname) { m_num_miss++; DYAD_LOG_INFO (NULL, " %s adds %s to set %u\n", \ - m_level.c_str (), fname.c_str (), m_id); + m_level.c_str (), id_str (fname).c_str (), m_id); if (m_size == m_block_set.size ()) { evict (); } - m_block_set.insert (Ranked_Block (fname, get_priority ())); + m_block_set.insert (Ranked_Block (fname, get_priority (PRT ()))); m_seqno++; } -void Set_Prioritized::access (id_iterator_t &it) +template +void Set_Prioritized::access (id_iterator_t &it) { - Ranked_Block blk = *it; + Ranked_Block blk = *it; // reassigning the priority - blk.m_priority = get_priority (); + blk.m_priority = get_priority (PRT ()); m_block_set.erase (it); m_block_set.insert (blk); m_seqno++; } -bool Set_Prioritized::access (const std::string& fname) +template +bool Set_Prioritized::access (const IDT& 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); + m_level.c_str (), id_str (fname).c_str (), m_id); access (it); return true; } else { // miss @@ -148,12 +176,14 @@ bool Set_Prioritized::access (const std::string& fname) } } -unsigned int Set_Prioritized::get_priority () +template +PRT Set_Prioritized::get_priority (PRT) { return m_seqno; } -std::ostream& Set_Prioritized::print (std::ostream &os) const +template +std::ostream& Set_Prioritized::print (std::ostream &os) const { os << "size : " << m_size << std::endl; os << "num accesses : " << m_seqno<< std::endl; @@ -170,4 +200,61 @@ std::ostream& Set_Prioritized::print (std::ostream &os) const return os; } +template +std::ostream& operator<<(std::ostream& os, const Set_Prioritized& cc) +{ + return cc.print (os); +} + + +namespace { +template +void __attribute__ ((unused)) instantiate_LRU () +{ + Set_LRU set_lru (1u, 1u, 0u); + T id; + set_lru.size (); + set_lru.get_num_access (); + set_lru.get_num_miss (); + set_lru.reset_cnts (); + set_lru.get_level (); + set_lru.set_level ("na"); + set_lru.access (id); + set_lru.print (std::cout); + std::cout << set_lru; +} + +template +void __attribute__ ((unused)) instantiate_Prioritized () +{ + Set_Prioritized set_prt (1u, 1u, 0u); + T id; + set_prt.size (); + set_prt.get_num_access (); + set_prt.get_num_miss (); + set_prt.reset_cnts (); + set_prt.get_level (); + set_prt.set_level ("na"); + set_prt.access (id); + set_prt.print (std::cout); + std::cout << set_prt; +} + +void __attribute__ ((unused)) instantiate_all () +{ + instantiate_LRU (); + instantiate_LRU (); + instantiate_LRU (); + + instantiate_Prioritized (); + instantiate_Prioritized (); + instantiate_Prioritized (); + + instantiate_Prioritized (); + instantiate_Prioritized (); + instantiate_Prioritized (); +} + +} // end of namespace + } // end of namespace dyad_residency diff --git a/src/dyad/residency/fcache.hpp b/src/dyad/residency/fcache.hpp index 4c71bb28..53908fdf 100644 --- a/src/dyad/residency/fcache.hpp +++ b/src/dyad/residency/fcache.hpp @@ -25,21 +25,34 @@ namespace dyad_residency { // Cache Block (cache line) for LRU //============================================================================= +template struct Simple_Block { - std::string m_id; // unique id, file name + IDT m_id; // unique id, file name - Simple_Block (const std::string& id) + Simple_Block (const IDT& id) : m_id (id) {} + + std::string id_str () const; }; +template struct Ranked_Block { - std::string m_id; // unique id, file name - unsigned int m_priority; // priority + IDT m_id; // unique id, file name + PRT m_priority; // priority - Ranked_Block (const std::string& id, unsigned int priority) + Ranked_Block (const IDT& id, PRT priority) : m_id (id), m_priority (priority) {} + + std::string id_str () const { + if constexpr (typeid (IDT) == typeid (std::string)) { + return m_id; + } else { + using namespace std; + return to_string (m_id); + } + } }; @@ -47,27 +60,33 @@ struct Ranked_Block // Associative Cache Set //============================================================================= +template class Set_LRU { + public: + using id_t = IDT; + protected: struct id{}; struct priority{}; - typedef boost::multi_index_container< - Simple_Block, + using Blk = Simple_Block; + + typedef typename boost::multi_index_container< + Blk, boost::multi_index::indexed_by< boost::multi_index::hashed_unique, - BOOST_MULTI_INDEX_MEMBER(Simple_Block, std::string, m_id)>, + BOOST_MULTI_INDEX_MEMBER(Blk, IDT, 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 typename boost::multi_index::index::type id_idx_t; + typedef typename boost::multi_index::index::type::iterator id_iterator_t; + typedef typename 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; + typedef typename boost::multi_index::index::type priority_idx_t; + typedef typename boost::multi_index::index::type::iterator priority_iterator_t; + typedef typename 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 @@ -91,11 +110,11 @@ class Set_LRU LRU_Blocks m_block_set; - virtual bool lookup (const std::string& fname, id_iterator_t &it); + virtual bool lookup (const IDT& 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 (); + virtual void load_and_access (const IDT& fname); + virtual unsigned int get_priority (unsigned int); public: Set_LRU(unsigned int sz, unsigned int n_sets, unsigned int id) @@ -112,60 +131,76 @@ class Set_LRU /** 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 bool access (const IDT& fname); virtual std::ostream& print (std::ostream &os) const; }; -std::ostream& operator<<(std::ostream& os, const Set_LRU & sl); +template +std::ostream& operator<<(std::ostream& os, const Set_LRU & sl); -class Set_Prioritized : public Set_LRU +template +class Set_Prioritized : public Set_LRU { + public: + using id_t = IDT; + using priority_t = PRT; + protected: struct id{}; struct priority{}; + using Blk = Ranked_Block; - typedef boost::multi_index_container< - Ranked_Block, + typedef typename boost::multi_index_container< + Blk, boost::multi_index::indexed_by< boost::multi_index::hashed_unique, - BOOST_MULTI_INDEX_MEMBER(Ranked_Block, std::string, m_id)>, + BOOST_MULTI_INDEX_MEMBER(Blk, IDT, m_id)>, boost::multi_index::ordered_non_unique, - BOOST_MULTI_INDEX_MEMBER(Ranked_Block, unsigned int, m_priority)> + BOOST_MULTI_INDEX_MEMBER(Blk, PRT, 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 typename boost::multi_index::index::type id_idx_t; + typedef typename boost::multi_index::index::type::iterator id_iterator_t; + typedef typename 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; + typedef typename boost::multi_index::index::type priority_idx_t; + typedef typename boost::multi_index::index::type::iterator priority_iterator_t; + typedef typename boost::multi_index::index::type::const_iterator priority_citerator_t; private: - using Set_LRU::lookup; - using Set_LRU::access; + using Set_LRU::lookup; + using Set_LRU::access; + using Set_LRU::get_priority; protected: + using Set_LRU::m_size; + using Set_LRU::m_num_sets; + using Set_LRU::m_id; + using Set_LRU::m_seqno; + using Set_LRU::m_num_miss; + using Set_LRU::m_level; + Prio_Blocks m_block_set; - virtual bool lookup (const std::string& fname, id_iterator_t &it); + virtual bool lookup (const IDT& 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 (); + virtual void load_and_access (const IDT& fname); + virtual PRT get_priority (PRT); public: Set_Prioritized (unsigned int sz, unsigned int n_sets, unsigned int id) - : Set_LRU (sz, n_sets, id) {} + : Set_LRU (sz, n_sets, id) {} virtual ~Set_Prioritized () {} - virtual bool access (const std::string& fname); + virtual bool access (const IDT& fname); virtual std::ostream& print (std::ostream &os) const; }; -std::ostream& operator<<(std::ostream& os, const Set_Prioritized & sp); +template +std::ostream& operator<<(std::ostream& os, const Set_Prioritized & sp); //============================================================================= // Set Associative Cache @@ -177,6 +212,7 @@ class Cache { public: using Sets = typename std::vector; + using id_t = typename Set::id_t; protected: unsigned int m_size; ///< Capacity of cache in terms of the number of blocks @@ -187,8 +223,6 @@ class Cache Sets m_set; - unsigned int get_cache_set_id (const std::string& fname) const; - public: Cache (unsigned int sz, unsigned int w); virtual ~Cache () {} @@ -205,7 +239,7 @@ class Cache void set_level (const std::string& level); /// Returns true if hit. Otherwise false. - virtual bool access (const std::string& fname); + virtual bool access (const id_t& fname); std::ostream& print (std::ostream &os) const; }; diff --git a/src/dyad/residency/fcache_impl.hpp b/src/dyad/residency/fcache_impl.hpp index 5c2bbf82..bb56e8bc 100644 --- a/src/dyad/residency/fcache_impl.hpp +++ b/src/dyad/residency/fcache_impl.hpp @@ -6,6 +6,25 @@ namespace dyad_residency { +unsigned int get_cache_set_id (const std::string& fname, const unsigned num_sets, const unsigned seed = 0u) +{ + 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), seed, hash); + return (hash[0] ^ hash[1] ^ hash[2] ^ hash[3]) % num_sets; +} + +unsigned int get_cache_set_id (const int fid, const unsigned num_sets, const unsigned seed = 0u) +{ + return fid % num_sets; +} + //============================================================================= // Cache //============================================================================= @@ -58,26 +77,11 @@ void Cache::reset_cnts (void) } 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) +bool Cache::access (const id_t& 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 = get_cache_set_id (fname, m_num_sets, m_seed); 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..8deceb4d 100644 --- a/src/dyad/residency/test_fcache.cpp +++ b/src/dyad/residency/test_fcache.cpp @@ -3,6 +3,8 @@ #include #include +using IDT = std::string; + int main (int argc, char** argv) { using namespace dyad_residency; @@ -10,13 +12,14 @@ int main (int argc, char** argv) int seed = 0; if (argc > 2) { + std::cout << "Usage: " << argv[0] << " [seed]" << std::endl; return EXIT_FAILURE; } if (argc == 2) { seed = atoi (argv[1]); } - typedef std::vector access; + typedef std::vector access; access acc; // access pattern in terms of the block index acc.push_back ("1"); acc.push_back ("4"); @@ -28,11 +31,11 @@ int main (int argc, char** argv) bool hitL1; #if 1 - Cache cacheL1 (4, 2); // 2-way set-associative - Cache cacheL2 (8, 2); // cache capacity = 8 blocks + 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 + Cache> cacheL1 (4, 2); + Cache> cacheL2 (8, 2); #endif cacheL1.set_seed (seed + 104677u); cacheL1.set_level ("L1");