LCOV - code coverage report
Current view: top level - memory_manager - sub_session.cpp (source / functions) Hit Total Coverage
Test: CoherentDB code coverage Lines: 136 164 82.9 %
Date: 2011-02-13 Functions: 24 28 85.7 %

          Line data    Source code
       1             : /*
       2             :  * (C) Copyright 2010 Xilexio
       3             :  *
       4             :  * This file is part of CoherentDB.
       5             :  *
       6             :  * CoherentDB is free software: you can redistribute it and/or modify it
       7             :  * under the terms of the GNU General Public License as published by
       8             :  * the Free Software Foundation, either version 3 of the License, or
       9             :  * (at your option) any later version.
      10             :  *
      11             :  * CoherentDB is distributed in the hope that it will be useful, but
      12             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      14             :  * General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public
      17             :  * License along with CoherentDB. If not, see
      18             :  * http://www.gnu.org/licenses/.
      19             :  */
      20             : 
      21             : #include <sys/mman.h>
      22             : #include <memory_manager/manager.h>
      23             : #include <memory_manager/session.h>
      24             : #include <memory_manager/sub_session.h>
      25             : #include <debug/asserts.h>
      26             : 
      27             : // TODO to config
      28             : static const double max_small_alloc_pages = 0.75;
      29             : static const size_t single_small_alloc_pages = 64;
      30             : 
      31             : namespace coherent
      32             : {
      33             : namespace memory_manager
      34             : {
      35             : 
      36             : typedef boost::shared_lock<boost::shared_mutex> scoped_read_lock;
      37             : typedef boost::unique_lock<boost::shared_mutex> scoped_write_lock;
      38             : typedef boost::unique_lock<boost::mutex> scoped_lock;
      39             : 
      40           0 : memory_sub_session::memory_sub_session(bool autostart) : allocated_bytes(0), parent(memory_session::current())
      41             : {
      42           0 :     internal_init(autostart);
      43           0 : }
      44             : 
      45           8 : memory_sub_session::memory_sub_session(memory_session* session, bool autostart) : allocated_bytes(0), parent(session)
      46             : {
      47           8 :     internal_init(autostart);
      48           8 : }
      49             : 
      50           8 : memory_sub_session::~memory_sub_session()
      51             : {
      52           8 :     end();
      53           8 : }
      54             : 
      55     8325866 : memory_sub_session* memory_sub_session::current()
      56             : {
      57     8325866 :     return memory_session::current_sub_session.get();
      58             : }
      59             : 
      60          35 : void memory_sub_session::begin()
      61             : {
      62          35 :     activate();
      63             : 
      64          33 :     scoped_lock am(active_threads_mutex);
      65          35 :     ++active_threads_count;
      66          35 : }
      67             : 
      68           8 : void memory_sub_session::end()
      69             : {
      70           8 :     deactivate();
      71             : 
      72          16 :     scoped_lock am(active_threads_mutex);
      73           8 :     if (active_threads_count > 0)
      74           8 :         --active_threads_count;
      75           8 : }
      76             : 
      77           0 : void memory_sub_session::stop()
      78             : {
      79           0 :     deactivate();
      80             : 
      81           0 :     scoped_lock am(active_threads_mutex);
      82             :     d_assert(active_threads_count > 0);
      83           0 :     --active_threads_count;
      84             : 
      85           0 :     if (active_threads_count == 0)
      86             :     {
      87           0 :         scoped_read_lock al(alloc_lock);
      88             : 
      89           0 :         for (std::map<byte*, size_t>::const_iterator i = allocs.begin(); i != allocs.end(); ++i)
      90             :         {
      91           0 :             if (madvise(i->first, i->second, MADV_DONTNEED))
      92             :                 LOG(WARN, "madvise error on freezing\n");
      93             :         }
      94             :     }
      95           0 : }
      96             : 
      97           0 : void memory_sub_session::resume()
      98             : {
      99             :     {
     100           0 :         scoped_lock am(active_threads_mutex);
     101           0 :         ++active_threads_count;
     102             : 
     103           0 :         if (active_threads_count == 1)
     104             :         {
     105           0 :             scoped_read_lock al(alloc_lock);
     106             : 
     107           0 :             for (std::map<byte*, size_t>::const_iterator i = allocs.begin(); i != allocs.end(); ++i)
     108             :             {
     109           0 :                 if (madvise(i->first, i->second, MADV_NORMAL))
     110             :                     LOG(ERROR, "madvise error on unfreezing\n");
     111             :             }
     112             :         }
     113             :     }
     114             : 
     115           0 :     activate();
     116           0 : }
     117             : 
     118          36 : void memory_sub_session::set_current()
     119             : {
     120          36 :     activate();
     121          36 : }
     122             : 
     123           0 : size_t memory_sub_session::get_allocated_bytes() const
     124             : {
     125           0 :     scoped_read_lock al(alloc_lock);
     126           0 :     return allocated_bytes;
     127             : }
     128             : 
     129     8348092 : memory_session* memory_sub_session::get_parent() const
     130             : {
     131     8348092 :     return parent;
     132             : }
     133             : 
     134           8 : void memory_sub_session::internal_init(bool autostart)
     135             : {
     136           8 :     if (autostart)
     137           0 :         begin();
     138           8 : }
     139             : 
     140          71 : void memory_sub_session::activate()
     141             : {
     142          71 :     memory_session::current_sub_session.reset(this);
     143          69 : }
     144             : 
     145           8 : void memory_sub_session::deactivate()
     146             : {
     147           8 :     if (memory_session::current_sub_session.get() == this)
     148           0 :         memory_session::current_sub_session.reset();
     149           8 : }
     150             : 
     151     4180382 : byte* memory_sub_session::allocate(size_t needed_bytes)
     152             : {
     153     4180382 :     size_t page_size = memory_manager::instance->get_page_size();
     154             : 
     155             :     byte* res;
     156             : 
     157     4182791 :     if (needed_bytes > max_small_alloc_pages * page_size)
     158             :     {
     159        8239 :         size_t bytes = (needed_bytes + page_size - 1) / page_size * page_size;
     160             : 
     161        8239 :         byte* p = reinterpret_cast<byte*> (mmap(0, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0));
     162             : 
     163        8240 :         if (p == MAP_FAILED)
     164           0 :             throw std::bad_alloc();
     165             : 
     166        8240 :         add_alloc(p, bytes);
     167             : 
     168        8240 :         res = p;
     169             :     }
     170             :     else
     171             :     {
     172     4174552 :         std::pair<size_t, byte*> optimal_chunk = smallest_sufficent_free_small_chunk(needed_bytes);
     173             : 
     174             :         size_t remainder_size;
     175             : 
     176     4162134 :         if (optimal_chunk.first == 0)
     177             :         {
     178           7 :             size_t bytes = single_small_alloc_pages * page_size;
     179             : 
     180           7 :             byte* p = reinterpret_cast<byte*> (mmap(0, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0));
     181             : 
     182           8 :             if (p == MAP_FAILED)
     183           0 :                 throw std::bad_alloc();
     184             : 
     185           8 :             add_alloc(p, bytes);
     186           8 :             add_small_alloc(p, needed_bytes);
     187             : 
     188           8 :             res = p;
     189             : 
     190           8 :             remainder_size = bytes - needed_bytes;
     191             :         }
     192             :         else
     193             :         {
     194     4162127 :             remainder_size = optimal_chunk.first - needed_bytes;
     195             : 
     196     4162127 :             add_small_alloc(optimal_chunk.second, needed_bytes);
     197     4168924 :             remove_free_small_chunk(optimal_chunk.second);
     198             : 
     199     4151403 :             res = optimal_chunk.second;
     200             :         }
     201             : 
     202     4151411 :         if (remainder_size != 0)
     203             :         {
     204     1703407 :             byte* remainder_pointer = res + needed_bytes;
     205             : 
     206     1703407 :             add_free_small_chunk(remainder_pointer, remainder_size);
     207             :         }
     208             :     }
     209             : 
     210     4159780 :     return res;
     211             : }
     212             : 
     213     4185168 : void memory_sub_session::deallocate(byte* p, size_t bytes)
     214             : {
     215             :     // TODO assertions for bytes
     216             : 
     217     4185168 :     if (is_small_alloc(p))
     218             :     {
     219             :         // removing chunk
     220     4171198 :         remove_small_alloc(p);
     221             : 
     222     4165086 :         std::pair<byte*, size_t> chunk_alloc = free_small_chunk_alloc(p);
     223     4160813 :         std::pair<byte*, size_t> remainder = add_merge_remove_free_small_chunk(p, bytes);
     224             : 
     225     4174070 :         if (chunk_alloc.second == remainder.second)
     226             :         {
     227           8 :             if (munmap(chunk_alloc.first, chunk_alloc.second))
     228             :                 LOG(WARN, "unmap error\n");
     229             : 
     230           8 :             remove_alloc(chunk_alloc.first);
     231             :         }
     232             :         else
     233             :         {
     234     4174062 :             add_free_small_chunk(remainder.first, remainder.second);
     235             :         }
     236             :     }
     237             :     else
     238             :     {
     239        8240 :         if (munmap(reinterpret_cast<void*> (p), bytes))
     240             :             LOG(WARN, "unmap error\n");
     241             : 
     242        8240 :         remove_alloc(p);
     243             :     }
     244     4167846 : }
     245             : 
     246        8247 : void memory_sub_session::add_alloc(byte* p, size_t bytes)
     247             : {
     248        8247 :     allocated_bytes += bytes;
     249        8247 :     allocs.insert(std::make_pair(p, bytes));
     250             : 
     251        8246 :     parent->allocated_bytes += bytes;
     252        8246 :     parent->allocs.insert(std::make_pair(p, this));
     253        8247 : }
     254             : 
     255        8248 : void memory_sub_session::remove_alloc(byte* p)
     256             : {
     257        8248 :     std::map<byte*, size_t>::iterator i = allocs.find(p);
     258             :     d_assert(i != allocs.end());
     259             : 
     260        8247 :     size_t bytes = i->second;
     261             : 
     262        8248 :     allocated_bytes -= bytes;
     263        8248 :     allocs.erase(i);
     264             : 
     265        8248 :     parent->allocated_bytes -= bytes;
     266        8248 :     parent->allocs.insert(std::make_pair(p, this));
     267        8248 : }
     268             : 
     269     4170335 : std::pair<size_t, byte*> memory_sub_session::smallest_sufficent_free_small_chunk(size_t bytes)
     270             : {
     271     4170335 :     std::set<std::pair<size_t, byte*> >::iterator i = free_small_chunks_inv.upper_bound(std::make_pair(bytes, (byte*) 0));
     272             : 
     273     4176512 :     if (i == free_small_chunks_inv.end())
     274           7 :         return std::make_pair(0, (byte*) 0);
     275             :     else
     276     4165565 :         return *i;
     277             : }
     278             : 
     279     4160235 : void memory_sub_session::add_small_alloc(byte* p, size_t bytes)
     280             : {
     281     4160235 :     small_allocs.insert(std::make_pair(p, bytes));
     282     4177599 : }
     283             : 
     284     4167824 : void memory_sub_session::remove_small_alloc(byte* p)
     285             : {
     286     4167824 :     std::set<std::pair<byte*, size_t> >::const_iterator i = small_allocs.upper_bound(std::make_pair(p, 0));
     287             :     d_assert(i != small_allocs.end());
     288             :     d_assert(i->first == p);
     289             : 
     290     4171414 :     small_allocs.erase(i);
     291     4168383 : }
     292             : 
     293     4184261 : bool memory_sub_session::is_small_alloc(byte* p) const
     294             : {
     295     4184261 :     std::set<std::pair<byte*, size_t> >::iterator sa = small_allocs.upper_bound(std::make_pair(p, 0));
     296             : 
     297     4182114 :     return sa != small_allocs.end() && sa->first == p;
     298             : }
     299             : 
     300     5857846 : void memory_sub_session::add_free_small_chunk(byte* p, size_t bytes)
     301             : {
     302     5857846 :     free_small_chunks.insert(std::make_pair(p, bytes));
     303     5860341 :     free_small_chunks_inv.insert(std::make_pair(bytes, p));
     304     5849840 : }
     305             : 
     306     4164203 : void memory_sub_session::remove_free_small_chunk(byte* p)
     307             : {
     308     4164203 :     free_small_chunks_inv.erase(std::make_pair(free_small_chunks[p], p));
     309     4158450 :     free_small_chunks.erase(p);
     310     4156741 : }
     311             : 
     312     8311988 : std::pair<byte*, size_t> memory_sub_session::free_small_chunk_alloc(byte* p) const
     313             : {
     314     8311988 :     std::map<byte*, size_t>::const_iterator chunk_alloc = allocs.upper_bound(p);
     315             :     d_assert(chunk_alloc != allocs.begin());
     316     8318485 :     --chunk_alloc;
     317             : 
     318     8316567 :     return *chunk_alloc;
     319             : }
     320             : 
     321     4160758 : std::pair<byte*, size_t> memory_sub_session::add_merge_remove_free_small_chunk(byte* p, size_t bytes)
     322             : {
     323     4160758 :     std::pair<byte*, size_t> chunk_alloc = free_small_chunk_alloc(p);
     324             : 
     325     4167428 :     size_t remainder_size = bytes;
     326     4167428 :     byte* remainder_pointer = p;
     327             : 
     328     4167428 :     if (!free_small_chunks.empty())
     329             :     {
     330             :         // adding and merging free space
     331     4164407 :         std::map<byte*, size_t>::iterator next = free_small_chunks.upper_bound(remainder_pointer);
     332             : 
     333     4166408 :         if (next != free_small_chunks.begin())
     334             :         {
     335     2269952 :             std::map<byte*, size_t>::iterator previous = next;
     336     2269952 :             --previous;
     337             : 
     338     2270918 :             if (previous->first >= chunk_alloc.first)
     339             :             {
     340             :                 d_assert(remainder_pointer > previous->first);
     341             : 
     342     2271204 :                 size_t diff = remainder_pointer - previous->first;
     343             :                 d_assert(diff >= previous->second);
     344             : 
     345     2267311 :                 if (diff == previous->second)
     346             :                 {
     347      183089 :                     remainder_pointer = previous->first;
     348      183088 :                     remainder_size += previous->second;
     349             : 
     350      183100 :                     free_small_chunks_inv.erase(std::make_pair(previous->second, previous->first));
     351      183084 :                     free_small_chunks.erase(previous);
     352             : 
     353      183086 :                     next = free_small_chunks.upper_bound(remainder_pointer);
     354             :                 }
     355             :             }
     356             :         }
     357             : 
     358     4172017 :         if (next != free_small_chunks.end() && remainder_size != chunk_alloc.second)
     359             :         {
     360             :             d_assert(next->first > remainder_pointer);
     361             : 
     362     4168155 :             size_t diff = next->first - remainder_pointer;
     363             : 
     364     4167286 :             if (diff == remainder_size)
     365             :             {
     366     1523607 :                 remainder_size += next->second;
     367             : 
     368     1523587 :                 free_small_chunks_inv.erase(std::make_pair(next->second, next->first));
     369     1524082 :                 free_small_chunks.erase(next);
     370             :             }
     371             :         }
     372             :     }
     373             : 
     374     4168917 :     return std::make_pair(remainder_pointer, remainder_size);
     375             : }
     376             : 
     377             : }
     378           3 : }

Generated by: LCOV version 1.9