summary |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
daa7210)
With a simple hash, we expect collision to happen: when inserting a
new page in the store, each stored page with the same hash is compared
(memcmp-ed) with the current page. If a page already present is
inserted, the content of the stored page is always pulled in the
cache: when inserting n pages, into the page store at least 2×n pages
are pulled in the cache.
With this option, a collision-free fingerprint of each page is
computed. As there is no collision, we do not have to check the
content of the stored pages. MD4 is used as we do not need security
against malicious users and it is much faster than more sescure
cryptographic hashes.
+if(enable_mc_content_adressable_pages)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMC_PAGE_STORE_MD4")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMC_PAGE_STORE_MD4")
+endif()
+
if(APPLE AND COMPILER_C_VERSION_MAJOR_MINOR MATCHES "4.6")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-deprecated-declarations")
set(optCFLAGS "-O0 ")
if(APPLE AND COMPILER_C_VERSION_MAJOR_MINOR MATCHES "4.6")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-deprecated-declarations")
set(optCFLAGS "-O0 ")
SET(SIMGRID_DEP "${SIMGRID_DEP} -lgtnets")
endif()
SET(SIMGRID_DEP "${SIMGRID_DEP} -lgtnets")
endif()
+if(enable_mc_content_adressable_pages)
+ SET(SIMGRID_DEP "${SIMGRID_DEP} -lnettle")
+endif()
+
if(HAVE_MC)
# The availability of libunwind was checked in CompleteInFiles.cmake
# (that includes FindLibunwind.cmake), so simply load it now.
if(HAVE_MC)
# The availability of libunwind was checked in CompleteInFiles.cmake
# (that includes FindLibunwind.cmake), so simply load it now.
option(enable_print_message "Enable print message during config." off)
mark_as_advanced(enable_print_message)
option(enable_model-checking "Turn this on to experiment with our prototype of model-checker (hinders the simulation's performance even if turned of at runtime)" off)
option(enable_print_message "Enable print message during config." off)
mark_as_advanced(enable_print_message)
option(enable_model-checking "Turn this on to experiment with our prototype of model-checker (hinders the simulation's performance even if turned of at runtime)" off)
+option(enable_mc_content_adressable_pages "Content addressable page storage (rely on the hash of the pages for page snapshot)" off)
option(enable_lib_static "" off)
option(enable_lib_in_jar "Whether the native libraries are bundled into the Java jar file" on)
option(enable_jedule "Jedule output of SimDAG." off)
option(enable_lib_static "" off)
option(enable_lib_in_jar "Whether the native libraries are bundled into the Java jar file" on)
option(enable_jedule "Jedule output of SimDAG." off)
#include "mc_page_store.h"
#include "mc_page_store.h"
+#ifdef MC_PAGE_STORE_MD4
+#include <nettle/md4.h>
+#endif
+
#include "mc_mmu.h"
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_page_snapshot, mc,
#include "mc_mmu.h"
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_page_snapshot, mc,
/** @brief Compte a hash for the given memory page
*
* The page is used before inserting the page in the page store
/** @brief Compte a hash for the given memory page
*
* The page is used before inserting the page in the page store
- * in order to find duplicate of this pae in the page store.
+ * in order to find duplicate of this page in the page store.
*
* @param data Memory page
* @return hash off the page
*/
static inline __attribute__ ((always_inline))
*
* @param data Memory page
* @return hash off the page
*/
static inline __attribute__ ((always_inline))
-uint64_t mc_hash_page(const void* data)
+s_mc_pages_store::hash_type mc_hash_page(const void* data)
+#ifdef MC_PAGE_STORE_MD4
+ boost::array<uint64_t,2> result;
+ md4_ctx context;
+ md4_init(&context);
+ md4_update(&context, xbt_pagesize, (const uint8_t*) data);
+ md4_digest(&context, MD4_DIGEST_SIZE, (uint8_t*) &(result[0]));
+ return result;
+#else
const uint64_t* values = (const uint64_t*) data;
size_t n = xbt_pagesize / sizeof(uint64_t);
const uint64_t* values = (const uint64_t*) data;
size_t n = xbt_pagesize / sizeof(uint64_t);
hash = ((hash << 5) + hash) + values[i];
}
return hash;
hash = ((hash << 5) + hash) + values[i];
}
return hash;
}
// ***** snapshot_page_manager
}
// ***** snapshot_page_manager
{
this->free_pages_.push_back(pageno);
const void* page = this->get_page(pageno);
{
this->free_pages_.push_back(pageno);
const void* page = this->get_page(pageno);
- uint64_t hash = mc_hash_page(page);
+ hash_type hash = mc_hash_page(page);
+#ifdef MC_PAGE_STORE_MD4
+ this->hash_index_.erase(hash);
+#else
this->hash_index_[hash].erase(pageno);
this->hash_index_[hash].erase(pageno);
}
/** Store a page in memory */
}
/** Store a page in memory */
// 1. compute the hash of the page;
// 2. find pages with the same hash using `hash_index_`;
// 3. find a page with the same content.
// 1. compute the hash of the page;
// 2. find pages with the same hash using `hash_index_`;
// 3. find a page with the same content.
- uint64_t hash = mc_hash_page(page);
+ hash_type hash = mc_hash_page(page);
+#ifdef MC_PAGE_STORE_MD4
+ s_mc_pages_store::pages_map_type::const_iterator i =
+ this->hash_index_.find(hash);
+ if (i!=this->hash_index_.cend()) {
+ // If a page with the same content is already in the page store it is
+ // reused and its reference count is incremented.
+ size_t pageno = i->second;
+ page_counts_[pageno]++;
+ return pageno;
+ }
+#else
+
+ // Try to find a duplicate in set of pages with the same hash:
page_set_type& page_set = this->hash_index_[hash];
BOOST_FOREACH (size_t pageno, page_set) {
const void* snapshot_page = this->get_page(pageno);
page_set_type& page_set = this->hash_index_[hash];
BOOST_FOREACH (size_t pageno, page_set) {
const void* snapshot_page = this->get_page(pageno);
// Otherwise, a new page is allocated in the page store and the content
// of the page is `memcpy()`-ed to this new page.
// Otherwise, a new page is allocated in the page store and the content
// of the page is `memcpy()`-ed to this new page.
xbt_assert(this->page_counts_[pageno]==0, "Allocated page is already used");
void* snapshot_page = (void*) this->get_page(pageno);
memcpy(snapshot_page, page, xbt_pagesize);
xbt_assert(this->page_counts_[pageno]==0, "Allocated page is already used");
void* snapshot_page = (void*) this->get_page(pageno);
memcpy(snapshot_page, page, xbt_pagesize);
+#ifdef MC_PAGE_STORE_MD4
+ this->hash_index_[hash] = pageno;
+#else
page_counts_[pageno]++;
return pageno;
}
page_counts_[pageno]++;
return pageno;
}
#ifdef __cplusplus
#include <vector>
#ifdef __cplusplus
#include <vector>
+#include <boost/array.hpp>
#include <boost/utility.hpp>
#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>
#include <boost/utility.hpp>
#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>
*
*/
struct s_mc_pages_store {
*
*/
struct s_mc_pages_store {
+public: // Types
+#ifdef MC_PAGE_STORE_MD4
+ typedef boost::array<uint64_t,2> hash_type;
+#else
typedef uint64_t hash_type;
typedef uint64_t hash_type;
- typedef boost ::unordered_set<size_t> page_set_type;
+#endif
+private: // Types
+#ifdef MC_PAGE_STORE_MD4
+ // We are using a secure hash to identify a page.
+ // We assume there will not be any collision: we need to map a hash
+ // to a single page index.
+ typedef boost::unordered_map<hash_type, size_t> pages_map_type;
+#else
+ // We are using a cheap hash to index a page.
+ // We should expect collision and we need to associate multiple page indices
+ // to the same hash.
+ typedef boost::unordered_set<size_t> page_set_type;
typedef boost::unordered_map<hash_type, page_set_type> pages_map_type;
typedef boost::unordered_map<hash_type, page_set_type> pages_map_type;
private: // Fields:
/** First page
private: // Fields:
/** First page