From d5c192b2262219c3b61037a2519f6a5838048feb Mon Sep 17 00:00:00 2001 From: Matthias Petri Date: Fri, 30 Aug 2013 01:15:47 +1000 Subject: [PATCH 1/7] first version of the new simplified memory management --- include/sdsl/construct.hpp | 20 +- include/sdsl/csa_sada.hpp | 20 +- include/sdsl/csa_wt.hpp | 16 +- include/sdsl/cst_sada.hpp | 12 +- include/sdsl/cst_sct3.hpp | 12 +- include/sdsl/int_vector.hpp | 19 +- include/sdsl/memory_management.hpp | 328 ++++++++++++++--------------- lib/construct_lcp.cpp | 80 +++---- lib/memory_management.cpp | 110 +--------- tutorial/mm-log.cpp | 9 +- 10 files changed, 252 insertions(+), 374 deletions(-) diff --git a/include/sdsl/construct.hpp b/include/sdsl/construct.hpp index 613b805c7..59c2f76ac 100644 --- a/include/sdsl/construct.hpp +++ b/include/sdsl/construct.hpp @@ -94,7 +94,7 @@ void construct(t_index& idx, const std::string& file, cache_config& config, uint template void construct(t_index& idx, const std::string& file, cache_config& config, uint8_t num_bytes, wt_tag) { - mm::log("wt-begin"); + memory_monitor::event("wt-begin"); int_vector text; load_vector_from_file(text, file, num_bytes); std::string tmp_key = util::to_string(util::pid())+"_"+util::to_string(util::id()); @@ -107,7 +107,7 @@ void construct(t_index& idx, const std::string& file, cache_config& config, uint idx.swap(tmp); } sdsl::remove(tmp_file_name); - mm::log("wt-end"); + memory_monitor::event("wt-end"); } // Specialization for CSAs @@ -121,23 +121,23 @@ void construct(t_index& idx, const std::string& file, cache_config& config, uint // (1) check, if the text is cached if (!cache_file_exists(KEY_TEXT, config)) { text_type text; - mm::log("text-begin"); + memory_monitor::event("text-begin"); load_vector_from_file(text, file, num_bytes); if (contains_no_zero_symbol(text, file)) { append_zero_symbol(text); store_to_cache(text, KEY_TEXT, config); } load_from_cache(text, KEY_TEXT, config); - mm::log("text-end"); + memory_monitor::event("text-end"); } register_cache_file(KEY_TEXT, config); } { // (2) check, if the suffix array is cached if (!cache_file_exists(constants::KEY_SA, config)) { - mm::log("sa-begin"); + memory_monitor::event("sa-begin"); construct_sa(config); - mm::log("sa-end"); + memory_monitor::event("sa-end"); } register_cache_file(constants::KEY_SA, config); int_vector<> sa; @@ -146,9 +146,9 @@ void construct(t_index& idx, const std::string& file, cache_config& config, uint { // (3) construct BWT if (!cache_file_exists(KEY_BWT, config)) { - mm::log("bwt-begin"); + memory_monitor::event("bwt-begin"); construct_bwt(config); - mm::log("bwt-end"); + memory_monitor::event("bwt-end"); } register_cache_file(constants::KEY_BWT, config); int_vector bwt; @@ -187,13 +187,13 @@ void construct(t_index& idx, const std::string& file, cache_config& config, uint register_cache_file(KEY_BWT, config); register_cache_file(constants::KEY_SA, config); if (!cache_file_exists(constants::KEY_LCP, config)) { - mm::log("lcp-begin"); + memory_monitor::event("lcp-begin"); if (t_index::alphabet_category::WIDTH==8) { construct_lcp_semi_extern_PHI(config); } else { construct_lcp_PHI(config); } - mm::log("lcp-end"); + memory_monitor::event("lcp-end"); } register_cache_file(constants::KEY_LCP, config); } diff --git a/include/sdsl/csa_sada.hpp b/include/sdsl/csa_sada.hpp index 9859493c1..993937127 100644 --- a/include/sdsl/csa_sada.hpp +++ b/include/sdsl/csa_sada.hpp @@ -362,18 +362,18 @@ csa_sada bwt_buf(cache_file_name(key_trait::KEY_BWT,config)); size_type n = bwt_buf.size(); - mm::log("csa-alphabet-construct-begin"); + memory_monitor::event("csa-alphabet-construct-begin"); { alphabet_type tmp_alphabet(bwt_buf, n); m_alphabet.swap(tmp_alphabet); } - mm::log("csa-alphabet-construct-end"); + memory_monitor::event("csa-alphabet-construct-end"); int_vector<> cnt_chr(sigma, 0, bits::hi(n)+1); for (typename alphabet_type::sigma_type i=0; i < sigma; ++i) { cnt_chr[i] = C[i]; } - mm::log("csa-psi-begin"); + memory_monitor::event("csa-psi-begin"); // calculate psi { // TODO: move PSI construct into construct_PSI.hpp @@ -386,25 +386,25 @@ csa_sada psi_buf(cache_file_name(constants::KEY_PSI, config)); - mm::log("csa-psi-encode-begin"); + memory_monitor::event("csa-psi-encode-begin"); { t_enc_vec tmp_psi(psi_buf); m_psi.swap(tmp_psi); } - mm::log("csa-psi-encode-end"); + memory_monitor::event("csa-psi-encode-end"); int_vector_buffer<> sa_buf(cache_file_name(constants::KEY_SA, config)); - mm::log("sa-sample-begin"); + memory_monitor::event("sa-sample-begin"); { sa_sample_type tmp_sa_sample(config); m_sa_sample.swap(tmp_sa_sample); } - mm::log("sa-sample-end"); + memory_monitor::event("sa-sample-end"); - mm::log("isa-sample-begin"); + memory_monitor::event("isa-sample-begin"); set_isa_samples(sa_buf, m_isa_sample); - mm::log("isa-sample-end"); + memory_monitor::event("isa-sample-end"); } template diff --git a/include/sdsl/csa_wt.hpp b/include/sdsl/csa_wt.hpp index 2a650d142..52b4bc200 100644 --- a/include/sdsl/csa_wt.hpp +++ b/include/sdsl/csa_wt.hpp @@ -276,30 +276,30 @@ csa_wt::cs int_vector_buffer bwt_buf(cache_file_name(key_trait::KEY_BWT,config)); int_vector_buffer<> sa_buf(cache_file_name(constants::KEY_SA, config)); size_type n = bwt_buf.size(); - mm::log("csa-alphabet-construct-begin"); + memory_monitor::event("csa-alphabet-construct-begin"); { alphabet_type tmp_alphabet(bwt_buf, n); m_alphabet.swap(tmp_alphabet); } - mm::log("csa-alphabet-construct-end"); + memory_monitor::event("csa-alphabet-construct-end"); - mm::log("wt-begin"); + memory_monitor::event("wt-begin"); { wavelet_tree_type tmp_wt(bwt_buf, n); m_wavelet_tree.swap(tmp_wt); } - mm::log("wt-end"); + memory_monitor::event("wt-end"); - mm::log("sa-sample-begin"); + memory_monitor::event("sa-sample-begin"); { sa_sample_type tmp_sa_sample(config); m_sa_sample.swap(tmp_sa_sample); } - mm::log("sa-sample-end"); + memory_monitor::event("sa-sample-end"); - mm::log("isa-sample-begin"); + memory_monitor::event("isa-sample-begin"); set_isa_samples(sa_buf, m_isa_sample); - mm::log("isa-sample-end"); + memory_monitor::event("isa-sample-end"); } diff --git a/include/sdsl/cst_sada.hpp b/include/sdsl/cst_sada.hpp index 0905e57f4..fb1e0ec18 100644 --- a/include/sdsl/cst_sada.hpp +++ b/include/sdsl/cst_sada.hpp @@ -145,7 +145,7 @@ class cst_sada //! Construct CST from file_map cst_sada(cache_config& config) { { - mm::log("bps-dfs-begin"); + memory_monitor::event("bps-dfs-begin"); cst_sct3<> temp_cst(config, true); m_bp.resize(4*(temp_cst.bp.size()/2)); util::set_to_value(m_bp, 0); @@ -158,19 +158,19 @@ class cst_sada ++idx; } m_bp.resize(idx); - mm::log("bps-dfs-end"); + memory_monitor::event("bps-dfs-end"); } - mm::log("bpss-dfs-begin"); + memory_monitor::event("bpss-dfs-begin"); util::assign(m_bp_support, bp_support_type(&m_bp)); util::init_support(m_bp_rank10, &m_bp); util::init_support(m_bp_select10, &m_bp); - mm::log("bpss-dfs-end"); + memory_monitor::event("bpss-dfs-end"); - mm::log("bpss-clcp-begin"); + memory_monitor::event("bpss-clcp-begin"); cache_config tmp_config(false, config.dir, config.id, config.file_map); construct_lcp(m_lcp, *this, tmp_config); config.file_map = tmp_config.file_map; - mm::log("bpss-clcp-end"); + memory_monitor::event("bpss-clcp-end"); load_from_cache(m_csa, util::class_to_hash(m_csa), config); } diff --git a/include/sdsl/cst_sct3.hpp b/include/sdsl/cst_sct3.hpp index e680d1811..830d5e297 100644 --- a/include/sdsl/cst_sct3.hpp +++ b/include/sdsl/cst_sct3.hpp @@ -1076,24 +1076,24 @@ class cst_sct3 template cst_sct3::cst_sct3(cache_config& config, bool build_only_bps) { - mm::log("bps-sct-begin"); + memory_monitor::event("bps-sct-begin"); int_vector_buffer<> lcp_buf(cache_file_name(constants::KEY_LCP, config)); m_nodes = construct_supercartesian_tree_bp_succinct_and_first_child(lcp_buf, m_bp, m_first_child) + m_bp.size()/2; if (m_bp.size() == 2) { // handle special case, when the tree consists only of the root node m_nodes = 1; } - mm::log("bps-sct-end"); - mm::log("bpss-sct-begin"); + memory_monitor::event("bps-sct-end"); + memory_monitor::event("bpss-sct-begin"); util::init_support(m_bp_support, &m_bp); util::init_support(m_first_child_rank, &m_first_child); - mm::log("bpss-sct-end"); + memory_monitor::event("bpss-sct-end"); if (!build_only_bps) { - mm::log("clcp-begin"); + memory_monitor::event("clcp-begin"); cache_config tmp_config(false, config.dir, config.id, config.file_map); construct_lcp(m_lcp, *this, tmp_config); config.file_map = tmp_config.file_map; - mm::log("clcp-end"); + memory_monitor::event("clcp-end"); } if (!build_only_bps) { load_from_cache(m_csa, util::class_to_hash(m_csa), config); diff --git a/include/sdsl/int_vector.hpp b/include/sdsl/int_vector.hpp index ac454098b..13c066608 100644 --- a/include/sdsl/int_vector.hpp +++ b/include/sdsl/int_vector.hpp @@ -21,12 +21,6 @@ #ifndef INCLUDED_SDSL_INT_VECTOR #define INCLUDED_SDSL_INT_VECTOR -#include - -#define HUGE_LEN 1073741824 -#define HUGE_PROTECTION (PROT_READ | PROT_WRITE) -#define HUGE_FLAGS (MAP_HUGETLB | MAP_ANONYMOUS | MAP_PRIVATE) - #include "compatibility.hpp" #include "bits.hpp" #include "structure_tree.hpp" @@ -54,7 +48,6 @@ #include #include - //! Namespace for the succinct data structure library. namespace sdsl { @@ -277,8 +270,7 @@ class int_vector friend class int_vector_const_iterator; friend class coder::elias_delta; friend class coder::fibonacci; - friend class mm_item; - friend class mm; + friend class memory_manager; friend void util::set_random_bits(int_vector& v, int); friend void util::_set_zero_bits(int_vector&); @@ -1118,7 +1110,6 @@ template inline int_vector::int_vector(size_type size, value_type default_value, uint8_t intWidth): m_size(0), m_data(nullptr), m_width(t_width) { - mm::add(this); width(intWidth); resize(size); util::set_to_value(*this, default_value); // new initialization @@ -1128,16 +1119,13 @@ template inline int_vector::int_vector(int_vector&& v) : m_size(v.m_size), m_data(v.m_data), m_width(v.m_width) { - v.m_size = 0; // has to be set for mm::remove v.m_data = nullptr; // ownership of v.m_data now transfered - mm::add(this, true); } template inline int_vector::int_vector(const int_vector& v): m_size(0), m_data(nullptr), m_width(v.m_width) { - mm::add(this); bit_resize(v.bit_size()); if (v.capacity() > 0) { if (memcpy(m_data, v.data() ,v.capacity()/8)==nullptr) { @@ -1173,8 +1161,7 @@ int_vector& int_vector::operator=(int_vector&& v) template int_vector::~int_vector() { - mm::remove(this); - free(m_data); + memory_manager::clear(*this); } template @@ -1196,7 +1183,7 @@ void int_vector::swap(int_vector& v) template void int_vector::bit_resize(const size_type size) { - mm::realloc(*this, size); + memory_manager::resize(*this, size); } template diff --git a/include/sdsl/memory_management.hpp b/include/sdsl/memory_management.hpp index 92939db0e..57810d7de 100644 --- a/include/sdsl/memory_management.hpp +++ b/include/sdsl/memory_management.hpp @@ -12,217 +12,197 @@ #include #include #include +#include namespace sdsl { -class mm_item_base +class memory_monitor; + +enum memformat_type {JSON, CSV, HTML}; +template +void write_mem_log(std::ostream& out,const memory_monitor& m); + +class memory_monitor { public: - mm_item_base() {}; - virtual bool map_hp(uint64_t*&) { - return false; - };// const = 0; - virtual bool unmap_hp() { - return false; - };// const = 0; - virtual ~mm_item_base() {}; - virtual uint64_t size() { - return 0; + using timer = std::chrono::high_resolution_clock; + struct mm_event { + timer::time_point timestamp; + uint64_t usage; + mm_event(timer::time_point t,uint64_t u) : timestamp(t) , usage(u) {}; }; -}; - -template -class mm_item : public mm_item_base -{ private: - int_vec_t* m_v; + std::chrono::milliseconds log_granularity = std::chrono::milliseconds(50); + uint64_t current_usage = 0; + uint64_t peak_usage = 0; + bool track_usage = false; + std::vector mem_events; + std::vector> events; + util::spin_lock spinlock; + private: + // disable construction of the object + memory_monitor() {}; + memory_monitor(const memory_monitor&) = delete; + memory_monitor& operator=(const memory_monitor&) = delete; + private: + static memory_monitor& the_monitor() { + static memory_monitor m; + return m; + } + static mm_event& last_event() { + auto& m = the_monitor(); + if (!m.mem_events.size()) { + m.mem_events.emplace_back(timer::now(),(uint64_t)0); + } + return m.mem_events.back(); // empty event + } public: - explicit mm_item(int_vec_t* v):m_v(v) {} - ~mm_item() { } - - //! Map content of int_vector to a hugepage starting at address addr - /*! - * Details: The content of the corresponding int_vector of mm_item - * is copied into a hugepage starting at address addr. - * The string position in the hugepage is then increased - * by the number of bytes used by the int_vector. - * So addr is the new starting address for the next - * mm_item which have to be mapped. - */ - bool map_hp(uint64_t*& addr) { - uint64_t len = size(); - if (m_v->m_data != nullptr) { - memcpy((char*)addr, m_v->m_data, len); // copy old data - free(m_v->m_data); - m_v->m_data = addr; - addr += (len/8); + static void granularity(std::chrono::milliseconds ms) { + auto& m = the_monitor(); + m.log_granularity = ms; + } + static void start() { + auto& m = the_monitor(); + m.track_usage = true; + event("start mem_monitor"); + } + static void stop() { + auto& m = the_monitor(); + event("stop mem_monitor"); + m.mem_events.emplace_back(timer::now(),m.current_usage); // final event + m.track_usage = false; + } + static void record(int64_t delta) { + auto& m = the_monitor(); + if (m.track_usage) { + std::lock_guard lock(m.spinlock); + m.current_usage = (uint64_t)((int64_t)m.current_usage + delta); + m.peak_usage = std::max(m.current_usage,m.peak_usage); + auto cur = timer::now(); + if (last_event().timestamp + m.log_granularity > cur) { + m.mem_events.emplace_back(cur,m.current_usage); + } } - return true; } - - //! - bool unmap_hp() { - uint64_t len = size(); - if (util::verbose) { - std::cerr<<"unmap int_vector of size "<< len <size()) { - log(""); - m_total_memory += item->size(); // add space - log(""); - } + private: + bool hugepages = false; + private: + static memory_manager& the_manager() { + static memory_manager m; + return m; + } + static uint64_t* alloc_mem(size_t size_in_bytes) { + auto& m = the_manager(); + if (m.hugepages) { + return hugepage_allocator::alloc(size_in_bytes); } else { - if (false and util::verbose) std::cout << "mm::add: mm_item is already in the set" << std::endl; + return (uint64_t*) calloc(size_in_bytes,1); } } - - template - static void realloc(int_vec_t& v, const typename int_vec_t::size_type size) { - bool do_realloc = ((size+63)>>6) != ((v.m_size+63)>>6); - uint64_t old_size = ((v.m_size+63)>>6)<<3; - v.m_size = size; // set new size - // special case: bitvector of size 0 - if (do_realloc or v.m_data==nullptr) { // or (t_width==1 and m_size==0) ) { - uint64_t* data = nullptr; + static void free_mem(uint64_t* ptr) { + auto& m = the_manager(); + if (m.hugepages) { + hugepage_allocator::free(ptr); + } else { + std::free(ptr); + } + } + public: + static void use_hugepages(size_t bytes) { + auto& m = the_manager(); + m.hugepages = true; + hugepage_allocator::init(bytes); + } + template + static void resize(t_vec& v, const typename t_vec::size_type size) { + int64_t old_size_in_bytes = ((v.m_size+63)>>6)<<3; + int64_t new_size_in_bytes = ((size+63)>>6)<<3; + std::cout << "resize(" << old_size_in_bytes << " , " << new_size_in_bytes << ")\n"; + bool do_realloc = old_size_in_bytes != new_size_in_bytes; + if (do_realloc || new_size_in_bytes == 0) { // Note that we allocate 8 additional bytes if m_size % 64 == 0. // We need this padding since rank data structures do a memory // access to this padding to answer rank(size()) if size()%64 ==0. // Note that this padding is not counted in the serialize method! - data = (uint64_t*)::realloc(v.m_data, (((v.m_size+64)>>6)<<3)); // if m_data == nullptr realloc - // Method realloc is equivalent to malloc if m_data == nullptr. - // If size is zero and ptr is not nullptr, a new, minimum sized object is allocated and the original object is freed. - // The allocated memory is aligned such that it can be used for any data type, including AltiVec- and SSE-related types. - v.m_data = data; - // initialize unreachable bits to 0 - if (v.bit_size() < v.capacity()) { //m_size>0 - bits::write_int(v.m_data+(v.bit_size()>>6), 0, v.bit_size()&0x3F, v.capacity() - v.bit_size()); + size_t allocated_bytes = (((size+64)>>6)<<3); + uint64_t* data = memory_manager::alloc_mem(allocated_bytes); + if (allocated_bytes != 0 && data == nullptr) { + throw std::bad_alloc(); } - if (((v.m_size) % 64) == 0) { // initialize unreachable bits with 0 - v.m_data[v.m_size/64] = 0; - } - } - if (old_size != ((v.m_size+63)>>6)<<3) { - log(""); - { - std::lock_guard lock(m_spinlock); - m_total_memory -= old_size; // subtract old space - m_total_memory += ((v.m_size+63)>>6)<<3; // add new space - } - log(""); - } - } + // copy and update + std::memcpy(data, v.m_data, std::min(old_size_in_bytes,new_size_in_bytes)); + memory_manager::free_mem(v.m_data); + v.m_data = data; + v.m_size = size; - template - static void remove(int_vec_t* v) { - std::lock_guard lock(m_spinlock); - if (mm::m_items.find((uint64_t)v) != mm::m_items.end()) { - if (false and util::verbose) { - std::cout << "mm:remove: remove vector " << v << std::endl; - }; - mm_item_base* item = m_items[(uint64_t)v]; - if (item->size()) { - log(""); - m_total_memory -= item->size(); // delete space - log(""); - } - mm::m_items.erase((uint64_t)v); - delete item; - } else { - if (false and util::verbose) { - std::cout << "mm:remove: mm_item is not in the set" << std::endl; - }; + // update stats + memory_monitor::record(new_size_in_bytes-old_size_in_bytes); } + std::cout << "done(" << old_size_in_bytes << " , " << new_size_in_bytes << ")\n"; } + template + static void clear(t_vec& v) { + int64_t size_in_bytes = ((v.m_size+63)>>6)<<3; - static void log_stream(std::ostream* out); + // remove mem + memory_manager::free_mem(v.m_data); + v.m_data = nullptr; - static void log_granularity(std::chrono::microseconds granularity); - - static void log(const std::string& msg) { - if (m_out != nullptr) { - auto cur = timer::now(); - auto log_time = cur-m_pre_rtime; - if (log_time >= m_granularity - or msg.size() > 0) { - (*m_out) << duration_cast(log_time).count() - << m_pre_max_mem << ";" - << "" << std::endl; - if (msg.size() > 0) { // output if msg is set - (*m_out) << duration_cast(log_time).count() << ";" - << m_total_memory << ";" - << msg << std::endl; - } - - m_pre_max_mem = m_total_memory; // reset memory - m_pre_rtime = cur; - } else { - m_pre_max_mem = std::max(m_pre_max_mem, m_total_memory); - } - } + // update stats + memory_monitor::record(size_in_bytes*-1); } - - static bool map_hp(); - static bool unmap_hp(); }; + + } // end namespace #endif diff --git a/lib/construct_lcp.cpp b/lib/construct_lcp.cpp index 4cf0fa8f5..c9387a7ab 100644 --- a/lib/construct_lcp.cpp +++ b/lib/construct_lcp.cpp @@ -28,7 +28,7 @@ void construct_lcp_semi_extern_PHI(cache_config& config) // n-1 is the maximum entry in SA int_vector<64> plcp((n-1+q)>>log_q); - mm::log("lcp-calc-sparse-phi-begin"); + memory_monitor::event("lcp-calc-sparse-phi-begin"); for (size_type i=0, sai_1=0; i < n; ++i) { // we can start at i=0. if SA[i]%q==0 // we set PHI[(SA[i]=n-1)%q]=0, since T[0]!=T[n-1] size_type sai = sa_buf[i]; @@ -41,15 +41,15 @@ void construct_lcp_semi_extern_PHI(cache_config& config) } sai_1 = sai; } - mm::log("lcp-calc-sparse-phi-end"); + memory_monitor::event("lcp-calc-sparse-phi-end"); - mm::log("lcp-load-text-begin"); + memory_monitor::event("lcp-load-text-begin"); int_vector<8> text; load_from_cache(text, constants::KEY_TEXT, config); - mm::log("lcp-load-text-end"); + memory_monitor::event("lcp-load-text-end"); - mm::log("lcp-calc-sparse-plcp-begin"); + memory_monitor::event("lcp-calc-sparse-plcp-begin"); for (size_type i=0,j,k,l=0; i < plcp.size(); ++i) { j = i< lcp_big(0, 0, bits::hi(n-1)+1);//nn, 0, bits::hi(n-1)+1); { - mm::log("lcp-init-phi-begin"); + memory_monitor::event("lcp-init-phi-begin"); size_type sa_n_1 = 0; // value for SA[n-1] bit_vector todo(n,0); // bit_vector todo indicates which values are > m in lcp_sml { @@ -570,9 +570,9 @@ void construct_lcp_goPHI(cache_config& config) b_1 = b; sai_1 = sai; } - mm::log("lcp-init-phi-end"); + memory_monitor::event("lcp-init-phi-end"); - mm::log("lcp-calc-plcp-begin"); + memory_monitor::event("lcp-calc-plcp-begin"); for (size_type i=0, ii=0, l=m+1,p=0; i < n and ii 0 and todo[i-1]) @@ -585,17 +585,17 @@ void construct_lcp_goPHI(cache_config& config) phi[ii++] = l; } } - mm::log("lcp-calc-plcp-end"); + memory_monitor::event("lcp-calc-plcp-end"); util::clear(text); - mm::log("lcp-calc-lcp-begin"); + memory_monitor::event("lcp-calc-lcp-begin"); lcp_big.resize(nn); for (size_type i = 0, ii = 0; i < n and ii m) { lcp_big[ii++] = phi[todo_rank(sa_buf[i])]; } } - mm::log("lcp-calc-lcp-end"); + memory_monitor::event("lcp-calc-lcp-end"); } store_to_cache(lcp_big, "lcp_big", config); } // end phase 2 @@ -629,14 +629,14 @@ void construct_lcp_bwt_based(cache_config& config) std::string lcp_file = cache_file_name(constants::KEY_LCP, config); // create WT - mm::log("lcp-bwt-create-wt-huff-begin"); + memory_monitor::event("lcp-bwt-create-wt-huff-begin"); wt_huff, select_support_scan<1>, select_support_scan<0>> wt_bwt; construct(wt_bwt, cache_file_name(constants::KEY_BWT, config)); uint64_t n = wt_bwt.size(); - mm::log("lcp-bwt-create-wt-huff-end"); + memory_monitor::event("lcp-bwt-create-wt-huff-end"); // init - mm::log("lcp-bwt-init-begin"); + memory_monitor::event("lcp-bwt-init-begin"); size_type lcp_value = 0; // current LCP value size_type lcp_value_offset = 0; // Largest LCP value in LCP array, that was written on disk size_type phase = 0; // Count how often the LCP array was written on disk @@ -680,9 +680,9 @@ void construct_lcp_bwt_based(cache_config& config) // create C-array std::vector C; // C-Array: C[i] = number of occurrences of characters < i in the input create_C_array(C, wt_bwt); - mm::log("lcp-bwt-init-begin-end"); + memory_monitor::event("lcp-bwt-init-begin-end"); // calculate lcp - mm::log("lcp-bwt-calc-values-begin"); + memory_monitor::event("lcp-bwt-calc-values-begin"); // calculate first intervals partial_lcp[0] = 0; @@ -707,7 +707,7 @@ void construct_lcp_bwt_based(cache_config& config) // calculate LCP values phase by phase while (intervals) { if (intervals < use_queue_and_wt && !queue_used) { - mm::log("lcp-bwt-bitvec2queue-begin"); + memory_monitor::event("lcp-bwt-bitvec2queue-begin"); util::clear(dict[target]); // copy from bitvector to queue @@ -720,10 +720,10 @@ void construct_lcp_bwt_based(cache_config& config) b2 = util::next_bit(dict[source], a2+1); } util::clear(dict[source]); - mm::log("lcp-bwt-bitvec2queue-end"); + memory_monitor::event("lcp-bwt-bitvec2queue-end"); } if (intervals >= use_queue_and_wt && queue_used) { - mm::log("lcp-bwt-queue2bitvec-begin"); + memory_monitor::event("lcp-bwt-queue2bitvec-begin"); dict[source].resize(2*(n+1)); util::set_to_value(dict[source], 0); @@ -735,7 +735,7 @@ void construct_lcp_bwt_based(cache_config& config) dict[target].resize(2*(n+1)); util::set_to_value(dict[target], 0); - mm::log("lcp-bwt-queue2bitvec-end"); + memory_monitor::event("lcp-bwt-queue2bitvec-end"); } if (intervals < use_queue_and_wt) { @@ -814,14 +814,14 @@ void construct_lcp_bwt_based(cache_config& config) } ++lcp_value; if (lcp_value>=lcp_value_max) { - mm::log("lcp-bwt-write-to-file-begin"); + memory_monitor::event("lcp-bwt-write-to-file-begin"); if (phase) { insert_lcp_values(partial_lcp, index_done, lcp_file, lcp_value, lcp_value_offset); } else { store_to_file(partial_lcp, lcp_file); } - mm::log("lcp-bwt-write-to-file-end"); - mm::log("lcp-bwt-resize-variables-begin"); + memory_monitor::event("lcp-bwt-write-to-file-end"); + memory_monitor::event("lcp-bwt-resize-variables-begin"); util::init_support(ds_rank_support, &index_done); // Create rank support // Recalculate lcp_value_max and resize partial_lcp @@ -837,20 +837,20 @@ void construct_lcp_bwt_based(cache_config& config) partial_lcp.resize(remaining_lcp_values); util::set_to_value(partial_lcp, 0); ++phase; - mm::log("lcp-bwt-resize-variables-end"); + memory_monitor::event("lcp-bwt-resize-variables-end"); } } - mm::log("lcp-bwt-calc-values-end"); + memory_monitor::event("lcp-bwt-calc-values-end"); // merge to file - mm::log("lcp-bwt-merge-to-file-begin"); + memory_monitor::event("lcp-bwt-merge-to-file-begin"); if (phase) { insert_lcp_values(partial_lcp, index_done, lcp_file, lcp_value, lcp_value_offset); } else { store_to_file(partial_lcp, lcp_file); } register_cache_file(constants::KEY_LCP, config); - mm::log("lcp-bwt-merge-to-file-end"); + memory_monitor::event("lcp-bwt-merge-to-file-end"); } void construct_lcp_bwt_based2(cache_config& config) @@ -863,14 +863,14 @@ void construct_lcp_bwt_based2(cache_config& config) std::string tmp_lcp_file = cache_file_name(constants::KEY_LCP, config)+"_tmp"; // (1) Calculate LCP-Positions-Array: For each lcp_value (in ascending order) all its occurrences (in any order) in the lcp array { - mm::log("lcp-bwt2-create-wt-huff-begin"); + memory_monitor::event("lcp-bwt2-create-wt-huff-begin"); wt_huff, select_support_scan<1>, select_support_scan<0>> wt_bwt; construct(wt_bwt, cache_file_name(constants::KEY_BWT, config)); n = wt_bwt.size(); - mm::log("lcp-bwt2-create-wt-huff-begin"); + memory_monitor::event("lcp-bwt2-create-wt-huff-begin"); // Declare needed variables - mm::log("lcp-bwt2-init-begin"); + memory_monitor::event("lcp-bwt2-init-begin"); size_type intervals = 0; // Number of intervals which are currently stored size_type intervals_new = 0; // Number of new intervals @@ -896,9 +896,9 @@ void construct_lcp_bwt_based2(cache_config& config) // Create C-array std::vector C; // C-Array: C[i] = number of occurrences of characters < i in the input create_C_array(C, wt_bwt); - mm::log("lcp-bwt2-init-end"); + memory_monitor::event("lcp-bwt2-init-end"); // Calculate LCP-Positions-Array - mm::log("lcp-bwt2-calc-values-begin"); + memory_monitor::event("lcp-bwt2-calc-values-begin"); // Save position of first LCP-value lcp_positions_buf[idx_out_buf++] = 0; @@ -935,7 +935,7 @@ void construct_lcp_bwt_based2(cache_config& config) // Calculate LCP positions while (intervals) { if (intervals < use_queue_and_wt && !queue_used) { - mm::log("lcp-bwt2-bitvec2queue-begin"); + memory_monitor::event("lcp-bwt2-bitvec2queue-begin"); util::clear(dict[target]); // Copy from bitvector to queue @@ -949,10 +949,10 @@ void construct_lcp_bwt_based2(cache_config& config) b2 = util::next_bit(dict[source], a2+1); } util::clear(dict[source]); - mm::log("lcp-bwt2-bitvec2queue-end"); + memory_monitor::event("lcp-bwt2-bitvec2queue-end"); } if (intervals >= use_queue_and_wt && queue_used) { - mm::log("lcp-bwt2-queue2bitvec-begin"); + memory_monitor::event("lcp-bwt2-queue2bitvec-begin"); dict[source].resize(2*(n+1)); util::set_to_value(dict[source], 0); // Copy from queue to bitvector @@ -962,7 +962,7 @@ void construct_lcp_bwt_based2(cache_config& config) } dict[target].resize(2*(n+1)); util::set_to_value(dict[target], 0); - mm::log("lcp-bwt2-queue2bitvec-end"); + memory_monitor::event("lcp-bwt2-queue2bitvec-end"); } if (intervals < use_queue_and_wt) { @@ -1038,12 +1038,12 @@ void construct_lcp_bwt_based2(cache_config& config) ++lcp_value; new_lcp_value = true; } - mm::log("lcp-bwt2-calc-values-end"); + memory_monitor::event("lcp-bwt2-calc-values-end"); lcp_positions_buf.close(); } // (2) Insert LCP entires into LCP array { - mm::log("lcp-bwt2-reordering-begin"); + memory_monitor::event("lcp-bwt2-reordering-begin"); int_vector_buffer<> lcp_positions(tmp_lcp_file, std::ios::in, buffer_size); @@ -1077,7 +1077,7 @@ void construct_lcp_bwt_based2(cache_config& config) lcp_array.close(); register_cache_file(constants::KEY_LCP, config); lcp_positions.close(true); // close buffer and remove file - mm::log("lcp-bwt2-reordering-end"); + memory_monitor::event("lcp-bwt2-reordering-end"); } // End of phase 2 } diff --git a/lib/memory_management.cpp b/lib/memory_management.cpp index cb4c8c40a..a0b6b849f 100644 --- a/lib/memory_management.cpp +++ b/lib/memory_management.cpp @@ -1,107 +1,19 @@ -#include "sdsl/memory_management.hpp" - -#include // for malloc and free -#include #include +#include "sdsl/memory_management.hpp" -#ifdef MAP_HUGETLB -#define HUGE_LEN 1073741824 -#define HUGE_PROTECTION (PROT_READ | PROT_WRITE) -#define HUGE_FLAGS (MAP_HUGETLB | MAP_ANONYMOUS | MAP_PRIVATE) -#endif - -static int nifty_counter = 0; - -using timer = std::chrono::high_resolution_clock; - -std::map sdsl::mm::m_items; -uint64_t sdsl::mm::m_total_memory; -uint64_t* sdsl::mm::m_data; -std::ostream* sdsl::mm::m_out; -std::chrono::microseconds sdsl::mm::m_granularity; -timer::time_point sdsl::mm::m_pre_rtime; -uint64_t sdsl::mm::m_pre_max_mem; - -sdsl::util::spin_lock sdsl::mm::m_spinlock; - -sdsl::mm_initializer::mm_initializer() -{ - if (0 == nifty_counter++) { - mm::m_total_memory = 0; - mm::m_granularity = std::chrono::microseconds(500); - mm::m_pre_max_mem = 0; - // initialize static members object here - // mm::m_items.clear(); - mm::m_items = mm::tMVecItem(); - mm::m_data = nullptr; - mm::m_out = nullptr; - mm::m_pre_rtime = timer::now(); - } -} -sdsl::mm_initializer::~mm_initializer() -{ - if (0 == --nifty_counter) { - // clean up - } -} +using namespace std::chrono; -//! Namespace for the succinct data structure library -namespace sdsl +template<> +void write_mem_log(std::ostream& out,const memory_monitor& m) { + auto& m = the_monitor(); + // write header + out << "timestamp;memory_usage;event" << std::endl; -bool mm::map_hp() -{ -#ifdef MAP_HUGETLB - size_t hpgs= (m_total_memory+HUGE_LEN-1)/HUGE_LEN; // number of huge pages required to store the int_vectors - m_data = (uint64_t*)mmap(nullptr, hpgs*HUGE_LEN, HUGE_PROTECTION, HUGE_FLAGS, 0, 0); - if (m_data == MAP_FAILED) { - std::cout << "mmap was not successful" << std::endl; - return false; - } - // map int_vectors - uint64_t* addr = m_data; - bool success = true; - for (tMVecItem::const_iterator it=m_items.begin(); it!=m_items.end(); ++it) { - success = success && it->second->map_hp(addr); - } - return success; -#else - return false; -#endif -} - -bool mm::unmap_hp() -{ -#ifdef MAP_HUGETLB - size_t hpgs= (m_total_memory+HUGE_LEN-1)/HUGE_LEN; // number of huge pages - bool success = true; - for (tMVecItem::const_iterator it=m_items.begin(); it!=m_items.end(); ++it) { - success = success && it->second->unmap_hp(); - } -// uint64_t* tmp_data = (uint64_t*)malloc(m_total_memory); // allocate memory for int_vectors -// memcpy(tmp_data, m_data, len); // copy data from the mmapped region - int ret = munmap((void*)m_data, hpgs*HUGE_LEN); - if (ret == -1) { - perror("Unmap failed"); - return false; + auto first_ts = m.mem_events[0].timestamp; + for (const auto& event : m.mem_events) { + std::cout << duration_cast(event.timestamp-first_ts) << ";" + << event.memory_usage << ";\n"; } - return success; -#else - return true; -#endif } - -void mm::log_stream(std::ostream* out) -{ - std::lock_guard lock(m_spinlock); - m_out = out; -} - -void mm::log_granularity(std::chrono::microseconds granularity) -{ - std::lock_guard lock(m_spinlock); - m_granularity = granularity; -} - -} // end namespace diff --git a/tutorial/mm-log.cpp b/tutorial/mm-log.cpp index 8019d509d..2eae35839 100644 --- a/tutorial/mm-log.cpp +++ b/tutorial/mm-log.cpp @@ -8,15 +8,14 @@ using namespace std; int main(int argc, char* argv[]) { // set granularity of logging to 20 milliseconds - mm::log_granularity(std::chrono::milliseconds(20)); - // connect cout to the logging stream - mm::log_stream(&cout); + memory_monitor::granularity(std::chrono::milliseconds(20)); + // generate CST - mm::log("begin"); + memory_monitor::event("begin"); { cst_sct3<> cst; construct(cst, argv[1], 1); cerr< Date: Fri, 30 Aug 2013 09:46:00 +1000 Subject: [PATCH 2/7] more updates to the new memory management system --- include/sdsl/memory_management.hpp | 8 ++++---- lib/memory_management.cpp | 11 +++++++---- tutorial/mm-log.cpp | 8 ++++++-- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/include/sdsl/memory_management.hpp b/include/sdsl/memory_management.hpp index 57810d7de..7d27ce566 100644 --- a/include/sdsl/memory_management.hpp +++ b/include/sdsl/memory_management.hpp @@ -20,6 +20,7 @@ namespace sdsl class memory_monitor; enum memformat_type {JSON, CSV, HTML}; + template void write_mem_log(std::ostream& out,const memory_monitor& m); @@ -32,7 +33,6 @@ class memory_monitor uint64_t usage; mm_event(timer::time_point t,uint64_t u) : timestamp(t) , usage(u) {}; }; - private: std::chrono::milliseconds log_granularity = std::chrono::milliseconds(50); uint64_t current_usage = 0; uint64_t peak_usage = 0; @@ -94,7 +94,7 @@ class memory_monitor } template static void write_memory_log(std::ostream& out) { - write_mem_log(out,the_monitor); + write_mem_log(out,the_monitor()); } }; @@ -165,7 +165,7 @@ class memory_manager static void resize(t_vec& v, const typename t_vec::size_type size) { int64_t old_size_in_bytes = ((v.m_size+63)>>6)<<3; int64_t new_size_in_bytes = ((size+63)>>6)<<3; - std::cout << "resize(" << old_size_in_bytes << " , " << new_size_in_bytes << ")\n"; + //std::cout << "resize(" << old_size_in_bytes << " , " << new_size_in_bytes << ")\n"; bool do_realloc = old_size_in_bytes != new_size_in_bytes; if (do_realloc || new_size_in_bytes == 0) { // Note that we allocate 8 additional bytes if m_size % 64 == 0. @@ -186,7 +186,7 @@ class memory_manager // update stats memory_monitor::record(new_size_in_bytes-old_size_in_bytes); } - std::cout << "done(" << old_size_in_bytes << " , " << new_size_in_bytes << ")\n"; + //std::cout << "done(" << old_size_in_bytes << " , " << new_size_in_bytes << ")\n"; } template static void clear(t_vec& v) { diff --git a/lib/memory_management.cpp b/lib/memory_management.cpp index a0b6b849f..469896978 100644 --- a/lib/memory_management.cpp +++ b/lib/memory_management.cpp @@ -3,17 +3,20 @@ using namespace std::chrono; +namespace sdsl +{ + template<> void write_mem_log(std::ostream& out,const memory_monitor& m) { - auto& m = the_monitor(); - // write header out << "timestamp;memory_usage;event" << std::endl; auto first_ts = m.mem_events[0].timestamp; for (const auto& event : m.mem_events) { - std::cout << duration_cast(event.timestamp-first_ts) << ";" - << event.memory_usage << ";\n"; + out << duration_cast(event.timestamp-first_ts).count() << ";" + << event.usage << ";\n"; } } + +} diff --git a/tutorial/mm-log.cpp b/tutorial/mm-log.cpp index 2eae35839..0137d3da1 100644 --- a/tutorial/mm-log.cpp +++ b/tutorial/mm-log.cpp @@ -11,11 +11,15 @@ int main(int argc, char* argv[]) memory_monitor::granularity(std::chrono::milliseconds(20)); // generate CST - memory_monitor::event("begin"); + memory_monitor::start(); { cst_sct3<> cst; construct(cst, argv[1], 1); cerr<(of); + of.close(); } From cfefd8a8935b271b0dd707b12b8aedaccb5b30a2 Mon Sep 17 00:00:00 2001 From: Matthias Petri Date: Fri, 30 Aug 2013 18:07:28 +1000 Subject: [PATCH 3/7] fixes to the new memory management system --- include/sdsl/int_vector.hpp | 3 ++- include/sdsl/memory_management.hpp | 36 +++++++++++++++++++----------- lib/memory_management.cpp | 23 ++++++++++++++++--- tutorial/mm-log.cpp | 6 ++--- 4 files changed, 48 insertions(+), 20 deletions(-) diff --git a/include/sdsl/int_vector.hpp b/include/sdsl/int_vector.hpp index 13c066608..56a1234e8 100644 --- a/include/sdsl/int_vector.hpp +++ b/include/sdsl/int_vector.hpp @@ -304,7 +304,7 @@ class int_vector int_vector(std::initializer_list il) : int_vector() { resize(il.size()); size_type idx = 0; - for (auto x : il) { +for (auto x : il) { (*this)[idx++] = x; } } @@ -1120,6 +1120,7 @@ inline int_vector::int_vector(int_vector&& v) : m_size(v.m_size), m_data(v.m_data), m_width(v.m_width) { v.m_data = nullptr; // ownership of v.m_data now transfered + v.m_size = 0; } template diff --git a/include/sdsl/memory_management.hpp b/include/sdsl/memory_management.hpp index 7d27ce566..2fec70a87 100644 --- a/include/sdsl/memory_management.hpp +++ b/include/sdsl/memory_management.hpp @@ -30,12 +30,12 @@ class memory_monitor using timer = std::chrono::high_resolution_clock; struct mm_event { timer::time_point timestamp; - uint64_t usage; - mm_event(timer::time_point t,uint64_t u) : timestamp(t) , usage(u) {}; + int64_t usage; + mm_event(timer::time_point t,int64_t u) : timestamp(t) , usage(u) {}; }; std::chrono::milliseconds log_granularity = std::chrono::milliseconds(50); - uint64_t current_usage = 0; - uint64_t peak_usage = 0; + int64_t current_usage = 0; + int64_t peak_usage = 0; bool track_usage = false; std::vector mem_events; std::vector> events; @@ -53,7 +53,7 @@ class memory_monitor static mm_event& last_event() { auto& m = the_monitor(); if (!m.mem_events.size()) { - m.mem_events.emplace_back(timer::now(),(uint64_t)0); + m.mem_events.emplace_back(timer::now(),(int64_t)0); } return m.mem_events.back(); // empty event } @@ -77,10 +77,11 @@ class memory_monitor auto& m = the_monitor(); if (m.track_usage) { std::lock_guard lock(m.spinlock); - m.current_usage = (uint64_t)((int64_t)m.current_usage + delta); + m.current_usage = (int64_t)((int64_t)m.current_usage + delta); m.peak_usage = std::max(m.current_usage,m.peak_usage); auto cur = timer::now(); - if (last_event().timestamp + m.log_granularity > cur) { + if (last_event().timestamp + m.log_granularity < cur) { + m.mem_events.emplace_back(cur,m.current_usage); } } @@ -104,8 +105,10 @@ class memory_monitor class hugepage_allocator { private: +#ifdef MAP_HUGETLB uint64_t* m_memory = nullptr; size_t m_mem_size = 0; +#endif private: static hugepage_allocator& the_allocator() { static hugepage_allocator a; @@ -113,6 +116,7 @@ class hugepage_allocator } public: static void init(size_t size_in_bytes) { +#ifdef MAP_HUGETLB auto& a = the_allocator(); a.m_mem_size = size_in_bytes; a.m_memory = (uint64_t*) mmap(nullptr, size_in_bytes, @@ -121,9 +125,12 @@ class hugepage_allocator if (a.m_memory == MAP_FAILED) { throw std::bad_alloc(); } +#else + throw std::bad_alloc(); +#endif } static uint64_t* alloc(size_t size_in_bytes) { - return (uint64_t*) malloc(size_in_bytes); + return (uint64_t*) calloc(size_in_bytes,1); } static void free(uint64_t* ptr) { free(ptr); @@ -165,7 +172,7 @@ class memory_manager static void resize(t_vec& v, const typename t_vec::size_type size) { int64_t old_size_in_bytes = ((v.m_size+63)>>6)<<3; int64_t new_size_in_bytes = ((size+63)>>6)<<3; - //std::cout << "resize(" << old_size_in_bytes << " , " << new_size_in_bytes << ")\n"; + std::cout << "resize(" << old_size_in_bytes << " , " << new_size_in_bytes << ")\n"; bool do_realloc = old_size_in_bytes != new_size_in_bytes; if (do_realloc || new_size_in_bytes == 0) { // Note that we allocate 8 additional bytes if m_size % 64 == 0. @@ -184,20 +191,23 @@ class memory_manager v.m_size = size; // update stats - memory_monitor::record(new_size_in_bytes-old_size_in_bytes); + if (do_realloc) { + memory_monitor::record(new_size_in_bytes-old_size_in_bytes); + } } - //std::cout << "done(" << old_size_in_bytes << " , " << new_size_in_bytes << ")\n"; + std::cout << "done(" << old_size_in_bytes << " , " << new_size_in_bytes << ")\n"; } template static void clear(t_vec& v) { int64_t size_in_bytes = ((v.m_size+63)>>6)<<3; - // remove mem memory_manager::free_mem(v.m_data); v.m_data = nullptr; // update stats - memory_monitor::record(size_in_bytes*-1); + if (size_in_bytes) { + memory_monitor::record(size_in_bytes*-1); + } } }; diff --git a/lib/memory_management.cpp b/lib/memory_management.cpp index 469896978..e6f33d86a 100644 --- a/lib/memory_management.cpp +++ b/lib/memory_management.cpp @@ -13,10 +13,27 @@ void write_mem_log(std::ostream& out,const memory_monitor& m) out << "timestamp;memory_usage;event" << std::endl; auto first_ts = m.mem_events[0].timestamp; - for (const auto& event : m.mem_events) { - out << duration_cast(event.timestamp-first_ts).count() << ";" - << event.usage << ";\n"; + auto cur_event = m.events[0]; +for (const auto& event : m.mem_events) { + out << duration_cast(event.timestamp-first_ts).count() << ";" << event.usage << ";"; } } +template<> +void write_mem_log(std::ostream& out,const memory_monitor& m) +{ + // write header + out << "["; + + auto first_ts = m.mem_events[0].timestamp; + auto cur_event = m.events[0]; + for (size_t i=0; i(event.timestamp-first_ts).count() << "," << event.usage << "], "; + } + const auto& event = m.mem_events[m.mem_events.size()-1]; + out << "[" << duration_cast(event.timestamp-first_ts).count() << "," << event.usage << "] "; + out << "]"; +} + } diff --git a/tutorial/mm-log.cpp b/tutorial/mm-log.cpp index 0137d3da1..d7768aa49 100644 --- a/tutorial/mm-log.cpp +++ b/tutorial/mm-log.cpp @@ -8,7 +8,7 @@ using namespace std; int main(int argc, char* argv[]) { // set granularity of logging to 20 milliseconds - memory_monitor::granularity(std::chrono::milliseconds(20)); + memory_monitor::granularity(std::chrono::milliseconds(5)); // generate CST memory_monitor::start(); @@ -19,7 +19,7 @@ int main(int argc, char* argv[]) } memory_monitor::stop(); - std::ofstream of("test.csv"); - memory_monitor::write_memory_log(of); + std::ofstream of("test.json"); + memory_monitor::write_memory_log(of); of.close(); } From 22252b1d9e6b4b8207ce69a37ca134bb26e1e171 Mon Sep 17 00:00:00 2001 From: Matthias Petri Date: Tue, 10 Sep 2013 16:12:29 +1000 Subject: [PATCH 4/7] first working hugepage allocator version --- examples/hugepages.cpp | 18 +- include/sdsl/memory_management.hpp | 80 ++++--- lib/memory_management.cpp | 329 ++++++++++++++++++++++++++++- 3 files changed, 390 insertions(+), 37 deletions(-) diff --git a/examples/hugepages.cpp b/examples/hugepages.cpp index f84694d87..f130a1e5b 100644 --- a/examples/hugepages.cpp +++ b/examples/hugepages.cpp @@ -16,7 +16,7 @@ void do_something(const tCsa& csa) sum+=csa.psi(i); } auto stop = timer::now(); - cout << duration_cast(stop-start).count() << endl; + cout << "runtime in ms: " << duration_cast(stop-start).count() << endl; cout <<"sum="< csa; + auto start = timer::now(); construct(csa, argv[1], 1); + auto stop = timer::now(); + cout << "construction in ms: " << duration_cast(stop-start).count() << endl; do_something(csa); // before it is mapped - if (mm::map_hp()) { - cout << "Now the memory is mapped to hugepages " << endl; - do_something(csa); // while it is mapped - mm::unmap_hp(); - } else { - cout << "Not able to map the memory to hugepages" << endl; - } - do_something(csa); // after it is unmapped } diff --git a/include/sdsl/memory_management.hpp b/include/sdsl/memory_management.hpp index 2fec70a87..6bc9837f1 100644 --- a/include/sdsl/memory_management.hpp +++ b/include/sdsl/memory_management.hpp @@ -13,6 +13,9 @@ #include #include #include +#include +#include + namespace sdsl { @@ -99,41 +102,63 @@ class memory_monitor } }; +#pragma pack(push, 1) +typedef struct mm_block { + size_t size; + struct mm_block* next; + struct mm_block* prev; +} mm_block_t; + +typedef struct bfoot { + size_t size; +} mm_block_foot_t; +#pragma pack(pop) #include class hugepage_allocator { private: -#ifdef MAP_HUGETLB - uint64_t* m_memory = nullptr; - size_t m_mem_size = 0; -#endif + uint8_t* m_base = nullptr; + mm_block_t* m_first_block = nullptr; + uint8_t* m_top = nullptr; + size_t m_small_threshold = 4096; + size_t m_total_size = 0; + std::multimap m_free_large; private: - static hugepage_allocator& the_allocator() { - static hugepage_allocator a; - return a; - } + void coalesce_block(mm_block_t* block); + void split_block(mm_block_t* bptr,size_t size); + uint8_t* hsbrk(size_t size); + mm_block_t* new_block(size_t size); + void remove_from_free_set(mm_block_t* block); + void insert_into_free_set(mm_block_t* block); + mm_block_t* find_free_block(size_t size_in_bytes); public: - static void init(size_t size_in_bytes) { + void init(size_t size_in_bytes) { #ifdef MAP_HUGETLB - auto& a = the_allocator(); - a.m_mem_size = size_in_bytes; - a.m_memory = (uint64_t*) mmap(nullptr, size_in_bytes, - (PROT_READ | PROT_WRITE), - (MAP_HUGETLB | MAP_ANONYMOUS | MAP_PRIVATE), 0, 0); - if (a.m_memory == MAP_FAILED) { - throw std::bad_alloc(); + m_total_size = size_in_bytes; + m_base = (uint8_t*) mmap(nullptr, m_total_size, + (PROT_READ | PROT_WRITE), + (MAP_HUGETLB | MAP_ANONYMOUS | MAP_PRIVATE), 0, 0); + if (m_base == MAP_FAILED) { + throw std::system_error(ENOMEM,std::system_category(), + "hugepage_allocator could not allocate hugepages"); + } else { + // init the allocator + m_top = m_base; + m_first_block = (mm_block_t*) m_base; } #else - throw std::bad_alloc(); + throw std::system_error(ENOMEM,std::system_category(), + "hugepage_allocator: MAP_HUGETLB / hugepage support not available"); #endif } - static uint64_t* alloc(size_t size_in_bytes) { - return (uint64_t*) calloc(size_in_bytes,1); - } - static void free(uint64_t* ptr) { - free(ptr); + void* mm_realloc(void* ptr, size_t size); + void* mm_alloc(size_t size_in_bytes); + void mm_free(void* ptr); + static hugepage_allocator& the_allocator() { + static hugepage_allocator a; + return a; } }; @@ -146,10 +171,11 @@ class memory_manager static memory_manager m; return m; } + public: static uint64_t* alloc_mem(size_t size_in_bytes) { auto& m = the_manager(); if (m.hugepages) { - return hugepage_allocator::alloc(size_in_bytes); + return (uint64_t*) hugepage_allocator::the_allocator().mm_alloc(size_in_bytes); } else { return (uint64_t*) calloc(size_in_bytes,1); } @@ -157,7 +183,7 @@ class memory_manager static void free_mem(uint64_t* ptr) { auto& m = the_manager(); if (m.hugepages) { - hugepage_allocator::free(ptr); + hugepage_allocator::the_allocator().mm_free(ptr); } else { std::free(ptr); } @@ -166,13 +192,13 @@ class memory_manager static void use_hugepages(size_t bytes) { auto& m = the_manager(); m.hugepages = true; - hugepage_allocator::init(bytes); + hugepage_allocator::the_allocator().init(bytes); } template static void resize(t_vec& v, const typename t_vec::size_type size) { int64_t old_size_in_bytes = ((v.m_size+63)>>6)<<3; int64_t new_size_in_bytes = ((size+63)>>6)<<3; - std::cout << "resize(" << old_size_in_bytes << " , " << new_size_in_bytes << ")\n"; + //std::cout << "resize(" << old_size_in_bytes << " , " << new_size_in_bytes << ")\n"; bool do_realloc = old_size_in_bytes != new_size_in_bytes; if (do_realloc || new_size_in_bytes == 0) { // Note that we allocate 8 additional bytes if m_size % 64 == 0. @@ -195,7 +221,7 @@ class memory_manager memory_monitor::record(new_size_in_bytes-old_size_in_bytes); } } - std::cout << "done(" << old_size_in_bytes << " , " << new_size_in_bytes << ")\n"; + //std::cout << "done(" << old_size_in_bytes << " , " << new_size_in_bytes << ")\n"; } template static void clear(t_vec& v) { diff --git a/lib/memory_management.cpp b/lib/memory_management.cpp index e6f33d86a..e7f24eaed 100644 --- a/lib/memory_management.cpp +++ b/lib/memory_management.cpp @@ -14,7 +14,7 @@ void write_mem_log(std::ostream& out,const memory_monitor& m) auto first_ts = m.mem_events[0].timestamp; auto cur_event = m.events[0]; -for (const auto& event : m.mem_events) { + for (const auto& event : m.mem_events) { out << duration_cast(event.timestamp-first_ts).count() << ";" << event.usage << ";"; } } @@ -36,4 +36,331 @@ void write_mem_log(std::ostream& out,const memory_monitor& m) out << "]"; } +#define ALIGNMENT sizeof(uint64_t) +#define ALIGNSPLIT(size) (((size)) & ~0x7) +#define ALIGN(size) (((size) + (ALIGNMENT-1)) & ~0x7) +#define MM_BLOCK_OVERHEAD (sizeof(size_t)+sizeof(size_t)) +#define MIN_BLOCKSIZE (ALIGN(sizeof(mm_block_t)+sizeof(mm_block_foot_t))) +#define UNMASK_SIZE(size) ((size)&~1) +#define ISFREE(size) ((size)&1) +#define SETFREE(size) ((size)|1) +#define SPLIT_THRESHOLD (MIN_BLOCKSIZE) + + +/* from a memory location get the corresponding block header */ +using namespace sdsl; + +mm_block_t* +block_cur(void* ptr) +{ + mm_block_t* bptr = (mm_block_t*)((uint8_t*)ptr - sizeof(size_t)); + return bptr; +} + +/* given a block retrieve the previous block if any. nullptr otherwise */ +mm_block_t* +block_prev(mm_block_t* cur_bptr,mm_block_t* first) +{ + /* start of the heap? */ + if (cur_bptr == first) return nullptr; + mm_block_foot_t* prev_foot = (mm_block_foot_t*)((uint8_t*)cur_bptr - sizeof(mm_block_foot_t)); + mm_block_t* prev_bptr = (mm_block_t*)((uint8_t*)cur_bptr - UNMASK_SIZE(prev_foot->size)); + return prev_bptr; +} + +/* given a block retrieve the next block if any. nullptr otherwise */ +mm_block_t* +block_next(mm_block_t* cur_bptr,uint8_t* top) +{ + /* end of the heap? */ + if ((uint8_t*)((uint8_t*)cur_bptr+UNMASK_SIZE(cur_bptr->size)) >= top) return nullptr; + + mm_block_t* next_bptr = (mm_block_t*)((uint8_t*)cur_bptr + UNMASK_SIZE(cur_bptr->size)); + return next_bptr; +} + +/* calculate the size of a memory block */ +size_t +block_size(void* ptr) +{ + mm_block_t* bptr = block_cur(ptr); + return UNMASK_SIZE(bptr->size); +} + +bool +block_isfree(mm_block_t* ptr) +{ + ; + return ((ptr->size)&1ULL); +} + +/* is the next block free */ +bool +block_nextfree(mm_block_t* ptr,uint8_t* top) +{ + mm_block_t* next = block_next(ptr,top); + if (next && block_isfree(next)) return true; + return false; +} + +/* is the prev block free */ +bool +block_prevfree(mm_block_t* ptr,mm_block_t* begin) +{ + mm_block_t* prev = block_prev(ptr,begin); + if (prev && block_isfree(prev)) return 1; + return 0; +} + +/* update the footer with a new size */ +void +foot_update(mm_block_t* ptr,size_t size) +{ + mm_block_foot_t* fptr = (mm_block_foot_t*)((uint8_t*)ptr+ + UNMASK_SIZE(size)-sizeof(mm_block_foot_t)); + fptr->size = size; +} + +/* update the block with a new size */ +void +block_update(mm_block_t* ptr,size_t size) +{ + ptr->size = size; + foot_update(ptr,size); +} + +/* return the pointer to the "data" */ +void* +block_data(mm_block_t* ptr) +{ + return (void*)((uint8_t*)ptr+sizeof(size_t)); +} + +/* return size of the data that can be stored in the block */ +size_t +block_getdatasize(mm_block_t* ptr) +{ + size_t blocksize = UNMASK_SIZE(ptr->size); + return blocksize - sizeof(size_t) - sizeof(mm_block_foot_t); +} + +/* mark the block as free */ +void +block_markfree(mm_block_t* ptr) +{ + block_update(ptr,SETFREE(ptr->size)); +} + +/* mark the block as used */ +void +block_markused(mm_block_t* ptr) +{ + block_update(ptr,UNMASK_SIZE(ptr->size)); +} + + +void +hugepage_allocator::coalesce_block(mm_block_t* block) +{ + mm_block_t* newblock = block; + if (block_nextfree(block,m_top)) { + mm_block_t* next = block_next(block,m_top); + /* remove the "next" block from the free list */ + remove_from_free_set(next); + /* add the size of our block */ + block_update(block,UNMASK_SIZE(block->size)+UNMASK_SIZE(next->size)); + } + if (block_prevfree(block,m_first_block)) { + mm_block_t* prev = block_prev(block,m_first_block); + /* we remove the old prev block and readd it to the correct + size list if necessary */ + remove_from_free_set(prev); + newblock = prev; + block_update(prev,UNMASK_SIZE(prev->size)+UNMASK_SIZE(block->size)); + } + if (newblock) { + block_markfree(newblock); + insert_into_free_set(newblock); + } +} + + +void +hugepage_allocator::split_block(mm_block_t* bptr,size_t size) +{ + size_t blocksize = UNMASK_SIZE(bptr->size); + /* only split if we get at least a small block + out of it */ + int64_t newblocksize = ALIGNSPLIT(blocksize - ALIGN(size+MM_BLOCK_OVERHEAD)); + if (newblocksize >= (int64_t)SPLIT_THRESHOLD) { + /* update blocksize of old block */ + block_update(bptr,blocksize-newblocksize); + mm_block_t* newblock = (mm_block_t*)((char*)bptr+(blocksize-newblocksize)); + block_update(newblock,newblocksize); + block_markfree(newblock); + insert_into_free_set(newblock); + } +} + + +uint8_t* +hugepage_allocator::hsbrk(size_t size) +{ + ptrdiff_t left = (ptrdiff_t) m_total_size - (m_top - m_base); + if (left < (ptrdiff_t) size) { // enough space left? + throw std::system_error(ENOMEM,std::system_category(), + "hugepage_allocator: not enough hugepage memory available"); + } + uint8_t* new_mem = m_top; + m_top += size; + return new_mem; +} + +mm_block_t* +hugepage_allocator::new_block(size_t size) +{ + size = ALIGN(size+MM_BLOCK_OVERHEAD); + if (size < MIN_BLOCKSIZE) size = MIN_BLOCKSIZE; + mm_block_t* ptr = (mm_block_t*) hsbrk(size); + block_update(ptr,size); + return ptr; +} + +void +hugepage_allocator::remove_from_free_set(mm_block_t* block) +{ + auto eq_range = m_free_large.equal_range(block->size); + // find the block amoung the blocks with equal size + auto itr = eq_range.first; + auto last = eq_range.second; + auto found = m_free_large.end(); + while (itr != last) { + if (itr->second == block) { + found = itr; + } + ++itr; + } + if (found == m_free_large.end()) { + found = last; + } + m_free_large.erase(found); +} + +void +hugepage_allocator::insert_into_free_set(mm_block_t* block) +{ + m_free_large.emplace(block->size,block); +} + +mm_block_t* +hugepage_allocator::find_free_block(size_t size_in_bytes) +{ + mm_block_t* bptr = nullptr; + auto free_block = m_free_large.lower_bound(size_in_bytes); + if (free_block != m_free_large.end()) { + bptr = free_block->second; + m_free_large.erase(free_block); + } + return bptr; +} + +void* +hugepage_allocator::mm_alloc(size_t size_in_bytes) +{ + mm_block_t* bptr = nullptr; + if ((bptr=find_free_block(size_in_bytes + MM_BLOCK_OVERHEAD)) != nullptr) { + block_markused(bptr); + /* split if we have a block too large for us? */ + split_block(bptr,size_in_bytes); + } else { + bptr = new_block(size_in_bytes); + } + return block_data(bptr); +} + +void +hugepage_allocator::mm_free(void* ptr) +{ + if (ptr) { + mm_block_t* bptr = block_cur(ptr); + block_markfree(bptr); + /* coalesce if needed. otherwise just add */ + coalesce_block(bptr); + } +} + +void* +hugepage_allocator::mm_realloc(void* ptr, size_t size) +{ + + /* handle special cases first */ + if (ptr==NULL) return mm_alloc(size); + if (size==0) { + mm_free(ptr); + return NULL; + } + mm_block_t* bptr = block_cur(ptr); + + bool need_malloc = 0; + uint32_t blockdatasize = block_getdatasize(bptr); + /* we do nothing if the size is equal to the block */ + if (size == blockdatasize) + return ptr; /* do nothing if size fits already */ + if (size < blockdatasize) { + /* we shrink */ + /* do we shrink enough to perform a split? */ + split_block(bptr,size); + } else { + /* we expand */ + /* if the next block is free we could use it! */ + mm_block_t* next = block_next(bptr,m_top); + if (next && block_isfree(next)) { + /* do we have enough space if we use the next block */ + if (blockdatasize + UNMASK_SIZE(next->size) >= size) { + /* the next block is enough! */ + /* remove the "next" block from the free list */ + remove_from_free_set(next); + /* add the size of our block */ + block_update(bptr,UNMASK_SIZE(bptr->size)+UNMASK_SIZE(next->size)); + } else { + /* the next block is not enough. still used and get the leftover space + needed using sbrk */ + remove_from_free_set(next); + block_update(bptr,UNMASK_SIZE(bptr->size)+UNMASK_SIZE(next->size)); + /* request just enough so we fit */ + blockdatasize = block_getdatasize(bptr); + size_t needed = ALIGN(size - blockdatasize); + hsbrk(needed); + block_update(bptr,UNMASK_SIZE(bptr->size)+needed); + } + } else { + /* try combing the previous block if free */ + mm_block_t* prev = block_prev(bptr,m_first_block); + if (prev && block_isfree(prev)) { + if (blockdatasize + UNMASK_SIZE(prev->size) >= size) { + remove_from_free_set(prev); + size_t newsize = UNMASK_SIZE(prev->size)+UNMASK_SIZE(bptr->size); + block_update(prev,newsize); + /* move the data into the previous block */ + ptr = memmove(block_data(prev),ptr,blockdatasize); + } else { + /* not enough in the prev block */ + need_malloc = true; + } + } else { + /* prev block not free. get more memory */ + need_malloc = true; + } + } + } + if (need_malloc) { + void* newptr = mm_alloc(size); + memcpy(newptr,ptr,size); + mm_free(ptr); + ptr = newptr; + } + return ptr; +} + + } From c9c8c0771dfe09e7423b2bada7a3a345b81bf183 Mon Sep 17 00:00:00 2001 From: Matthias Petri Date: Wed, 11 Sep 2013 00:27:53 +1000 Subject: [PATCH 5/7] allow extending of the last block in a cheap way --- include/sdsl/memory_management.hpp | 29 +++++-- lib/memory_management.cpp | 129 ++++++++++++++++++++--------- 2 files changed, 113 insertions(+), 45 deletions(-) diff --git a/include/sdsl/memory_management.hpp b/include/sdsl/memory_management.hpp index 6bc9837f1..64b7bbd93 100644 --- a/include/sdsl/memory_management.hpp +++ b/include/sdsl/memory_management.hpp @@ -41,7 +41,7 @@ class memory_monitor int64_t peak_usage = 0; bool track_usage = false; std::vector mem_events; - std::vector> events; + std::vector> events; util::spin_lock spinlock; private: // disable construction of the object @@ -93,7 +93,7 @@ class memory_monitor auto& m = the_monitor(); if (m.track_usage) { std::lock_guard lock(m.spinlock); - m.events.emplace_back(timer::now(),name); + m.events.emplace_back(timer::now(),m.current_usage,name); } } template @@ -133,6 +133,8 @@ class hugepage_allocator void remove_from_free_set(mm_block_t* block); void insert_into_free_set(mm_block_t* block); mm_block_t* find_free_block(size_t size_in_bytes); + mm_block_t* last_block(); + void print_heap(); public: void init(size_t size_in_bytes) { #ifdef MAP_HUGETLB @@ -188,6 +190,14 @@ class memory_manager std::free(ptr); } } + static uint64_t* realloc_mem(uint64_t* ptr,size_t size) { + auto& m = the_manager(); + if (m.hugepages) { + return (uint64_t*) hugepage_allocator::the_allocator().mm_realloc(ptr,size); + } else { + return (uint64_t*) realloc(ptr,size); + } + } public: static void use_hugepages(size_t bytes) { auto& m = the_manager(); @@ -206,15 +216,18 @@ class memory_manager // access to this padding to answer rank(size()) if size()%64 ==0. // Note that this padding is not counted in the serialize method! size_t allocated_bytes = (((size+64)>>6)<<3); - uint64_t* data = memory_manager::alloc_mem(allocated_bytes); - if (allocated_bytes != 0 && data == nullptr) { + v.m_data = memory_manager::realloc_mem(v.m_data,allocated_bytes); + if (allocated_bytes != 0 && v.m_data == nullptr) { throw std::bad_alloc(); } - // copy and update - std::memcpy(data, v.m_data, std::min(old_size_in_bytes,new_size_in_bytes)); - memory_manager::free_mem(v.m_data); - v.m_data = data; + // update and fill with 0s v.m_size = size; + if (v.bit_size() < v.capacity()) { + bits::write_int(v.m_data+(v.bit_size()>>6), 0, v.bit_size()&0x3F, v.capacity() - v.bit_size()); + } + if (((v.m_size) % 64) == 0) { // initialize unreachable bits with 0 + v.m_data[v.m_size/64] = 0; + } // update stats if (do_realloc) { diff --git a/lib/memory_management.cpp b/lib/memory_management.cpp index e7f24eaed..93c4308d5 100644 --- a/lib/memory_management.cpp +++ b/lib/memory_management.cpp @@ -14,7 +14,7 @@ void write_mem_log(std::ostream& out,const memory_monitor& m) auto first_ts = m.mem_events[0].timestamp; auto cur_event = m.events[0]; - for (const auto& event : m.mem_events) { +for (const auto& event : m.mem_events) { out << duration_cast(event.timestamp-first_ts).count() << ";" << event.usage << ";"; } } @@ -22,17 +22,27 @@ void write_mem_log(std::ostream& out,const memory_monitor& m) template<> void write_mem_log(std::ostream& out,const memory_monitor& m) { - // write header out << "["; auto first_ts = m.mem_events[0].timestamp; - auto cur_event = m.events[0]; for (size_t i=0; i(event.timestamp-first_ts).count() << "," << event.usage << "], "; } const auto& event = m.mem_events[m.mem_events.size()-1]; out << "[" << duration_cast(event.timestamp-first_ts).count() << "," << event.usage << "] "; + out << "]" << std::endl; + + out << "["; + + for (size_t i=0; i(std::get<0>(ev)-first_ts).count() << ","<< std::get<1>(ev) << + ",\"" << std::get<2>(ev) << "\"], "; + } + const auto& ev = m.events[m.events.size()-1]; + out << "[" << duration_cast(std::get<0>(ev)-first_ts).count() << ","<< std::get<1>(ev) << + ",\"" << std::get<2>(ev) << "\"]"; out << "]"; } @@ -226,6 +236,37 @@ hugepage_allocator::new_block(size_t size) return ptr; } +mm_block_t* +hugepage_allocator::last_block() +{ + mm_block_t* last = nullptr; + if (m_top != m_base) { + mm_block_foot_t* fptr = (mm_block_foot_t*)(m_top - sizeof(size_t)); + last = (mm_block_t*)(((uint8_t*)fptr) - UNMASK_SIZE(fptr->size) + sizeof(size_t)); + } + return last; +} + +void +block_print(int id,mm_block_t* bptr) +{ + fprintf(stdout, "%d addr=%p size=%lu (%lu) free=%d\n",id,((void*)bptr), + UNMASK_SIZE(bptr->size),bptr->size,block_isfree(bptr)); + fflush(stdout); +} + +void +hugepage_allocator::print_heap() +{ + mm_block_t* bptr = m_first_block; + size_t id = 0; + while (bptr) { + block_print(id,bptr); + id++; + bptr = block_next(bptr,m_top); + } +} + void hugepage_allocator::remove_from_free_set(mm_block_t* block) { @@ -273,7 +314,19 @@ hugepage_allocator::mm_alloc(size_t size_in_bytes) /* split if we have a block too large for us? */ split_block(bptr,size_in_bytes); } else { - bptr = new_block(size_in_bytes); + // check if last block is free + bptr = last_block(); + if (bptr && block_isfree(bptr)) { + // extent last block as it is free + size_t blockdatasize = block_getdatasize(bptr); + size_t needed = ALIGN(size_in_bytes - blockdatasize); + hsbrk(needed); + remove_from_free_set(bptr); + block_update(bptr,UNMASK_SIZE(bptr->size)+needed); + insert_into_free_set(bptr); + } else { + bptr = new_block(size_in_bytes); + } } return block_data(bptr); } @@ -292,7 +345,6 @@ hugepage_allocator::mm_free(void* ptr) void* hugepage_allocator::mm_realloc(void* ptr, size_t size) { - /* handle special cases first */ if (ptr==NULL) return mm_alloc(size); if (size==0) { @@ -302,7 +354,7 @@ hugepage_allocator::mm_realloc(void* ptr, size_t size) mm_block_t* bptr = block_cur(ptr); bool need_malloc = 0; - uint32_t blockdatasize = block_getdatasize(bptr); + size_t blockdatasize = block_getdatasize(bptr); /* we do nothing if the size is equal to the block */ if (size == blockdatasize) return ptr; /* do nothing if size fits already */ @@ -314,42 +366,45 @@ hugepage_allocator::mm_realloc(void* ptr, size_t size) /* we expand */ /* if the next block is free we could use it! */ mm_block_t* next = block_next(bptr,m_top); - if (next && block_isfree(next)) { - /* do we have enough space if we use the next block */ - if (blockdatasize + UNMASK_SIZE(next->size) >= size) { - /* the next block is enough! */ - /* remove the "next" block from the free list */ - remove_from_free_set(next); - /* add the size of our block */ - block_update(bptr,UNMASK_SIZE(bptr->size)+UNMASK_SIZE(next->size)); - } else { - /* the next block is not enough. still used and get the leftover space - needed using sbrk */ - remove_from_free_set(next); - block_update(bptr,UNMASK_SIZE(bptr->size)+UNMASK_SIZE(next->size)); - /* request just enough so we fit */ - blockdatasize = block_getdatasize(bptr); - size_t needed = ALIGN(size - blockdatasize); - hsbrk(needed); - block_update(bptr,UNMASK_SIZE(bptr->size)+needed); - } + if (!next) { + // we are the last block so we just expand + blockdatasize = block_getdatasize(bptr); + size_t needed = ALIGN(size - blockdatasize); + hsbrk(needed); + block_update(bptr,UNMASK_SIZE(bptr->size)+needed); + return block_data(bptr); } else { - /* try combing the previous block if free */ - mm_block_t* prev = block_prev(bptr,m_first_block); - if (prev && block_isfree(prev)) { - if (blockdatasize + UNMASK_SIZE(prev->size) >= size) { - remove_from_free_set(prev); - size_t newsize = UNMASK_SIZE(prev->size)+UNMASK_SIZE(bptr->size); - block_update(prev,newsize); - /* move the data into the previous block */ - ptr = memmove(block_data(prev),ptr,blockdatasize); + // we are not the last block + if (next && block_isfree(next)) { + /* do we have enough space if we use the next block */ + if (blockdatasize + UNMASK_SIZE(next->size) >= size) { + /* the next block is enough! */ + /* remove the "next" block from the free list */ + remove_from_free_set(next); + /* add the size of our block */ + block_update(bptr,UNMASK_SIZE(bptr->size)+UNMASK_SIZE(next->size)); } else { - /* not enough in the prev block */ + /* the next block is not enough. we allocate a new one instead */ need_malloc = true; } } else { - /* prev block not free. get more memory */ - need_malloc = true; + /* try combing the previous block if free */ + mm_block_t* prev = block_prev(bptr,m_first_block); + if (prev && block_isfree(prev)) { + if (blockdatasize + UNMASK_SIZE(prev->size) >= size) { + remove_from_free_set(prev); + size_t newsize = UNMASK_SIZE(prev->size)+UNMASK_SIZE(bptr->size); + block_update(prev,newsize); + /* move the data into the previous block */ + ptr = memmove(block_data(prev),ptr,blockdatasize); + } else { + /* not enough in the prev block */ + need_malloc = true; + } + } else { + /* prev block not free. get more memory */ + need_malloc = true; + } } } } From 4cfa4af8fd92ddb661324fd64423d1f32f100dc4 Mon Sep 17 00:00:00 2001 From: Matthias Petri Date: Wed, 11 Sep 2013 10:07:07 +1000 Subject: [PATCH 6/7] More improvements to the new memory manager the memory manager now compiles with g++4.7. The hugepages example now shows how the memory monitor is used. --- examples/hugepages.cpp | 12 ++++++++++-- include/sdsl/memory_management.hpp | 2 +- lib/memory_management.cpp | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/examples/hugepages.cpp b/examples/hugepages.cpp index f130a1e5b..36c948982 100644 --- a/examples/hugepages.cpp +++ b/examples/hugepages.cpp @@ -16,7 +16,7 @@ void do_something(const tCsa& csa) sum+=csa.psi(i); } auto stop = timer::now(); - cout << "runtime in ms: " << duration_cast(stop-start).count() << endl; + cout << "runtime in s: " << duration_cast(stop-start).count() << endl; cout <<"sum="< csa; auto start = timer::now(); construct(csa, argv[1], 1); auto stop = timer::now(); - cout << "construction in ms: " << duration_cast(stop-start).count() << endl; + cout << "construction in s: " << duration_cast(stop-start).count() << endl; do_something(csa); // before it is mapped + + memory_monitor::stop(); + + std::ofstream ofs("cst-construction.json"); + memory_monitor::write_memory_log(ofs); + ofs.close(); } diff --git a/include/sdsl/memory_management.hpp b/include/sdsl/memory_management.hpp index 64b7bbd93..6051f6ab4 100644 --- a/include/sdsl/memory_management.hpp +++ b/include/sdsl/memory_management.hpp @@ -36,7 +36,7 @@ class memory_monitor int64_t usage; mm_event(timer::time_point t,int64_t u) : timestamp(t) , usage(u) {}; }; - std::chrono::milliseconds log_granularity = std::chrono::milliseconds(50); + std::chrono::milliseconds log_granularity = std::chrono::milliseconds(20); int64_t current_usage = 0; int64_t peak_usage = 0; bool track_usage = false; diff --git a/lib/memory_management.cpp b/lib/memory_management.cpp index 93c4308d5..09915546b 100644 --- a/lib/memory_management.cpp +++ b/lib/memory_management.cpp @@ -290,7 +290,7 @@ hugepage_allocator::remove_from_free_set(mm_block_t* block) void hugepage_allocator::insert_into_free_set(mm_block_t* block) { - m_free_large.emplace(block->size,block); + m_free_large.insert( {block->size,block}); } mm_block_t* From 4f12fdb3e96b62f3f9a0ea185cdea6bdd7496eab Mon Sep 17 00:00:00 2001 From: Matthias Petri Date: Wed, 11 Sep 2013 20:13:56 +1000 Subject: [PATCH 7/7] set file size even if we don't resize --- include/sdsl/memory_management.hpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/include/sdsl/memory_management.hpp b/include/sdsl/memory_management.hpp index 6051f6ab4..32ba22d8e 100644 --- a/include/sdsl/memory_management.hpp +++ b/include/sdsl/memory_management.hpp @@ -208,8 +208,8 @@ class memory_manager static void resize(t_vec& v, const typename t_vec::size_type size) { int64_t old_size_in_bytes = ((v.m_size+63)>>6)<<3; int64_t new_size_in_bytes = ((size+63)>>6)<<3; - //std::cout << "resize(" << old_size_in_bytes << " , " << new_size_in_bytes << ")\n"; bool do_realloc = old_size_in_bytes != new_size_in_bytes; + v.m_size = size; if (do_realloc || new_size_in_bytes == 0) { // Note that we allocate 8 additional bytes if m_size % 64 == 0. // We need this padding since rank data structures do a memory @@ -221,7 +221,6 @@ class memory_manager throw std::bad_alloc(); } // update and fill with 0s - v.m_size = size; if (v.bit_size() < v.capacity()) { bits::write_int(v.m_data+(v.bit_size()>>6), 0, v.bit_size()&0x3F, v.capacity() - v.bit_size()); } @@ -234,7 +233,6 @@ class memory_manager memory_monitor::record(new_size_in_bytes-old_size_in_bytes); } } - //std::cout << "done(" << old_size_in_bytes << " , " << new_size_in_bytes << ")\n"; } template static void clear(t_vec& v) { @@ -251,7 +249,6 @@ class memory_manager }; - } // end namespace #endif