kwave  18.07.70
Kwave::MemoryManager Class Reference

#include <MemoryManager.h>

Collaboration diagram for Kwave::MemoryManager:
Collaboration graph

Classes

struct  physical_memory_t
 

Public Member Functions

 MemoryManager ()
 
virtual ~MemoryManager ()
 
void close ()
 
Kwave::Handle allocate (size_t size) Q_DECL_EXPORT
 
bool resize (Kwave::Handle handle, size_t size) Q_DECL_EXPORT
 
size_t sizeOf (Kwave::Handle handle) Q_DECL_EXPORT
 
void free (Kwave::Handle &handle) Q_DECL_EXPORT
 
void setPhysicalLimit (quint64 mb) Q_DECL_EXPORT
 
void setVirtualLimit (quint64 mb) Q_DECL_EXPORT
 
void setSwapDirectory (const QString &dir) Q_DECL_EXPORT
 
void setUndoLimit (quint64 mb) Q_DECL_EXPORT
 
quint64 undoLimit () const Q_DECL_EXPORT
 
quint64 totalPhysical () Q_DECL_EXPORT
 
void * map (Kwave::Handle handle) Q_DECL_EXPORT
 
void unmap (Kwave::Handle handle) Q_DECL_EXPORT
 
int readFrom (Kwave::Handle handle, unsigned int offset, void *buffer, unsigned int length) Q_DECL_EXPORT
 
int writeTo (Kwave::Handle handle, unsigned int offset, const void *buffer, unsigned int length) Q_DECL_EXPORT
 

Static Public Member Functions

static MemoryManagerinstance () Q_DECL_EXPORT
 

Protected Member Functions

quint64 physicalUsed ()
 
quint64 virtualUsed ()
 
QString nextSwapFileName (Kwave::Handle handle)
 
bool convertToVirtual (Kwave::Handle handle, size_t new_size)
 
bool convertToPhysical (Kwave::Handle handle, size_t new_size)
 
Kwave::Handle allocatePhysical (size_t size)
 
void tryToMakePhysical (Kwave::Handle handle)
 
Kwave::Handle allocateVirtual (size_t size)
 

Private Types

typedef struct Kwave::MemoryManager::physical_memory_t physical_memory_t
 

Private Member Functions

Kwave::Handle newHandle ()
 
bool freePhysical (size_t size)
 
void unmapFromCache (Kwave::Handle handle)
 
void dump (const char *function)
 

Private Attributes

quint64 m_physical_limit
 
quint64 m_physical_max
 
quint64 m_virtual_limit
 
QDir m_swap_dir
 
quint64 m_undo_limit
 
Kwave::LRU_Cache< Kwave::Handle, physical_memory_tm_physical
 
QHash< Kwave::Handle, Kwave::SwapFile * > m_unmapped_swap
 
QHash< Kwave::Handle, Kwave::SwapFile * > m_mapped_swap
 
QHash< Kwave::Handle, Kwave::SwapFile * > m_cached_swap
 
QMutex m_lock
 

Static Private Attributes

static Kwave::Handle m_last_handle = 0
 

Detailed Description

Definition at line 39 of file MemoryManager.h.

Member Typedef Documentation

◆ physical_memory_t

Constructor & Destructor Documentation

◆ MemoryManager()

Kwave::MemoryManager::MemoryManager ( )

Constructor

Definition at line 56 of file MemoryManager.cpp.

References m_physical_limit, m_physical_max, and m_virtual_limit.

58  m_swap_dir(_("/tmp")), m_undo_limit(0),
61 {
62  // reset statistics
63 #ifdef DEBUG_MEMORY
64  memset(&m_stats, 0x00, sizeof(m_stats));
65 #endif /* DEBUG_MEMORY */
66 
67  // determine amount of physical memory
68  // start with 1/4 of the theoretical address space
69 
70  // if sizeof(void *) == 4 -> 32 bit -> 1024 MB
71  // if sizeof(void *) == 8 -> 64 bit -> 4.398E12 MB
72  quint64 total = (1ULL << ((sizeof(void *) * 8ULL) - 22ULL));
73 
74  // limit the total memory to a 32bit value [MB]
75  if (total > (1ULL << 32)) total = (1ULL << 32) - 1;
76 #ifdef DEBUG
77  qDebug("Kwave::MemoryManager: theoretical limit: %llu MB", total);
78 #endif /* DEBUG */
79 
80 #ifdef HAVE_SYSINFO
81  // get the physically installed memory
82  quint64 installed_physical;
83  struct sysinfo info;
84 
85  sysinfo(&info);
86 
87  // find out installed memory and convert to megabytes
88 #ifdef HAVE_SYSINFO_MEMUNIT
89  installed_physical = (info.totalram * info.mem_unit) >> 20;
90 #ifdef DEBUG
91  qDebug("Kwave::MemoryManager: sysinfo/memunit: %llu MB", installed_physical);
92 #endif /* DEBUG */
93 #else /* HAVE_SYSINFO_MEMUNIT */
94  installed_physical = info.totalram >> 20;
95  qDebug("Kwave::MemoryManager: sysinfo: %llu MB", installed_physical);
96 #endif /* HAVE_SYSINFO_MEMUNIT */
97  if (installed_physical && (installed_physical < total))
98  total = installed_physical;
99 #endif /* HAVE_SYSINFO */
100 
101 #ifdef HAVE_GETRLIMIT
102  struct rlimit limit;
103 
104  // check ulimit of data segment size
105  if (getrlimit(RLIMIT_DATA, &limit) == 0) {
106  quint64 physical_ulimit =
107  qMin(limit.rlim_cur, limit.rlim_max) >> 20;
108 #ifdef DEBUG
109  qDebug("Kwave::MemoryManager: RLIMIT_DATA: %llu MB", physical_ulimit);
110 #endif /* DEBUG */
111  if (physical_ulimit < total) total = physical_ulimit;
112  }
113 
114  // check ulimit of total (virtual) system memory (address space)
115 #ifdef RLIMIT_AS
116  if (getrlimit(RLIMIT_AS, &limit) == 0) {
117  quint64 total_ulimit =
118  qMin(limit.rlim_cur, limit.rlim_max) >> 20;
119 #ifdef DEBUG
120  qDebug("Kwave::MemoryManager: RLIMIT_AS: %llu MB", total_ulimit);
121 #endif /* DEBUG */
122  if (total_ulimit < total) total = total_ulimit;
123  }
124 #endif /* RLIMIT_AS */
125 #endif /* HAVE_GETRLIMIT */
126 
127  // limit the total memory to a int value [MB]
128  // (values go into the GUI)
129  total = qMin(total, static_cast<quint64>(INT_MAX));
130 
131 #ifdef DEBUG
132  qDebug("Kwave::MemoryManager: => using up to %llu MB RAM", total);
133 #endif /* DEBUG */
134 
135  m_physical_max = total;
136  m_physical_limit = total;
137 
138 #ifdef DEBUG_MEMORY
139  m_stats.physical.limit = m_physical_limit << 20ULL;
140  m_stats.swap.limit = m_virtual_limit << 20ULL;
141 #endif /* DEBUG_MEMORY */
142 }
QHash< Kwave::Handle, Kwave::SwapFile * > m_unmapped_swap
QHash< Kwave::Handle, Kwave::SwapFile * > m_mapped_swap
QHash< Kwave::Handle, Kwave::SwapFile * > m_cached_swap
#define _(m)
Definition: memcpy.c:66
Kwave::LRU_Cache< Kwave::Handle, physical_memory_t > m_physical

◆ ~MemoryManager()

Kwave::MemoryManager::~MemoryManager ( )
virtual

Destructor

Definition at line 145 of file MemoryManager.cpp.

References close().

146 {
147  close();
148 }
Here is the call graph for this function:

Member Function Documentation

◆ allocate()

Kwave::Handle Kwave::MemoryManager::allocate ( size_t  size)

Gets a block of memory, either in physical memory or in a swap file if there is not enough physical memory. If there is not enough memory at all, the return value will be a null pointer.

Parameters
sizenumber of bytes to allocate
Returns
handle of a storage object, to be used to be mapped into physical memory through map() or zero if out of memory

Definition at line 291 of file MemoryManager.cpp.

References allocatePhysical(), allocateVirtual(), dump(), freePhysical(), m_lock, and Kwave::toUint().

Referenced by Kwave::Stripe::StripeStorage::StripeStorage(), and Kwave::MimeData::Buffer::writeData().

292 {
293  QMutexLocker lock(&m_lock);
294 
295  Kwave::Handle handle = allocatePhysical(size);
296  if (!handle) {
297  // try to make some room in the physical memory area
298  if (freePhysical(size)) {
299  // and try again to allocate physical memory
300  handle = allocatePhysical(size);
301  }
302 
303  if (!handle) {
304  // fallback: allocate a swapfile
305  handle = allocateVirtual(size);
306  }
307  }
308 
309 #ifdef DEBUG_MEMORY
310  if (!handle) {
311  qWarning("Kwave::MemoryManager::allocate(%u) - out of memory!",
312  Kwave::toUint(size));
313  }
314  dump("allocate");
315 #endif /* DEBUG_MEMORY */
316 
317  return handle;
318 }
bool freePhysical(size_t size)
int Handle
Definition: MemoryManager.h:34
Kwave::Handle allocatePhysical(size_t size)
Kwave::Handle allocateVirtual(size_t size)
unsigned int toUint(T x)
Definition: Utils.h:109
void dump(const char *function)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ allocatePhysical()

Kwave::Handle Kwave::MemoryManager::allocatePhysical ( size_t  size)
protected

tries to allocate physical memory

Definition at line 321 of file MemoryManager.cpp.

References Kwave::MemoryManager::physical_memory_t::m_data, Kwave::MemoryManager::physical_memory_t::m_mapcount, m_physical, m_physical_limit, Kwave::MemoryManager::physical_memory_t::m_size, newHandle(), physicalUsed(), and totalPhysical().

Referenced by allocate(), and convertToPhysical().

322 {
323  // check for limits
324  quint64 limit = totalPhysical();
325  if (m_physical_limit < limit) limit = m_physical_limit;
326  quint64 used = physicalUsed();
327  quint64 available = (used < limit) ? (limit - used) : 0;
328  if ((size >> 20) >= available) return 0;
329 
330  // get a new handle
331  Kwave::Handle handle = newHandle();
332  if (!handle) return 0; // out of handles :-(
333 
334  // try to allocate via malloc
335  void *mem = ::malloc(size);
336  if (!mem) return 0; // out of memory :-(
337 
338  // store the object in the list of physical objects
339  physical_memory_t phys;
340  phys.m_data = mem;
341  phys.m_size = size;
342  phys.m_mapcount = 0;
343  Q_ASSERT(!m_physical.contains(handle));
344  m_physical.insert(handle, phys);
345 #ifdef DEBUG_MEMORY
346  m_stats.physical.handles++;
347  m_stats.physical.allocs++;
348  m_stats.physical.bytes += size;
349 #endif /* DEBUG_MEMORY */
350 
351  return handle;
352 }
quint64 totalPhysical() Q_DECL_EXPORT
Kwave::Handle newHandle()
int Handle
Definition: MemoryManager.h:34
struct Kwave::MemoryManager::physical_memory_t physical_memory_t
Kwave::LRU_Cache< Kwave::Handle, physical_memory_t > m_physical
Here is the call graph for this function:
Here is the caller graph for this function:

◆ allocateVirtual()

Kwave::Handle Kwave::MemoryManager::allocateVirtual ( size_t  size)
protected

Tries to allocate virtual memory

Parameters
sizenumber of bytes to allocate
Returns
handle of a SwapFile object or zero if failed

Definition at line 396 of file MemoryManager.cpp.

References Kwave::SwapFile::allocate(), dump(), m_unmapped_swap, m_virtual_limit, newHandle(), nextSwapFileName(), Kwave::toUint(), and virtualUsed().

Referenced by allocate(), and convertToVirtual().

397 {
398  // shortcut, if virtual memory is disabled
399  if (!m_virtual_limit)
400  return 0;
401 
402  // check for limits
403  quint64 limit = INT_MAX; // totalVirtual() in MB
404  if (m_virtual_limit < limit) limit = m_virtual_limit;
405  quint64 used = virtualUsed(); // in MB
406  quint64 available = (used < limit) ? (limit - used) : 0;
407  if ((size >> 20) >= available) {
408  qWarning("Kwave::MemoryManager::allocateVirtual(%u): out of memory, "\
409  "(used: %lluMB, available: %lluMB, limit=%lluMB)",
410  Kwave::toUint(size), used, available, limit);
411  dump("allocateVirtual");
412  return 0;
413  }
414 
415  // get a new handle
416  Kwave::Handle handle = newHandle();
417  if (!handle) return 0; // out of handles :-(
418 
419  // try to allocate
420  Kwave::SwapFile *swap = new Kwave::SwapFile(nextSwapFileName(handle));
421  Q_ASSERT(swap);
422  if (!swap) return 0; // out of memory :-(
423 
424  if (swap->allocate(size)) {
425  // succeeded, store the object in our map
426  m_unmapped_swap.insert(handle, swap);
427 #ifdef DEBUG_MEMORY
428  m_stats.swap.unmapped.bytes += size;
429  m_stats.swap.unmapped.handles++;
430  m_stats.swap.allocs++;
431 #endif /* DEBUG_MEMORY */
432  return handle;
433  } else {
434  qWarning("Kwave::MemoryManager::allocateVirtual(%u): OOM, "\
435  "(used: %lluMB) - failed resizing swap file",
436  Kwave::toUint(size), used);
437  // failed: give up, delete the swapfile object
438  delete swap;
439  }
440 
441  return 0;
442 }
QHash< Kwave::Handle, Kwave::SwapFile * > m_unmapped_swap
Kwave::Handle newHandle()
int Handle
Definition: MemoryManager.h:34
bool allocate(size_t size)
Definition: SwapFile.cpp:65
QString nextSwapFileName(Kwave::Handle handle)
unsigned int toUint(T x)
Definition: Utils.h:109
void dump(const char *function)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ close()

void Kwave::MemoryManager::close ( )

Closes the memory manager and does cleanups at program shutdown

Definition at line 151 of file MemoryManager.cpp.

References m_cached_swap, m_lock, m_mapped_swap, m_physical, and m_unmapped_swap.

Referenced by ~MemoryManager().

152 {
153  QMutexLocker lock(&m_lock);
154 
155  // print warnings for each physical memory block
156  Q_ASSERT(m_physical.isEmpty());
157 
158  // remove all remaining swap files and print warnings
159  Q_ASSERT(m_unmapped_swap.isEmpty());
160  Q_ASSERT(m_mapped_swap.isEmpty());
161  Q_ASSERT(m_cached_swap.isEmpty());
162 }
QHash< Kwave::Handle, Kwave::SwapFile * > m_unmapped_swap
QHash< Kwave::Handle, Kwave::SwapFile * > m_mapped_swap
QHash< Kwave::Handle, Kwave::SwapFile * > m_cached_swap
Kwave::LRU_Cache< Kwave::Handle, physical_memory_t > m_physical
Here is the caller graph for this function:

◆ convertToPhysical()

bool Kwave::MemoryManager::convertToPhysical ( Kwave::Handle  handle,
size_t  new_size 
)
protected

convert a swapfile into a physical memory block

Definition at line 489 of file MemoryManager.cpp.

References allocatePhysical(), dump(), Kwave::MemoryManager::physical_memory_t::m_data, m_physical, Kwave::MemoryManager::physical_memory_t::m_size, m_unmapped_swap, Kwave::SwapFile::read(), Kwave::SwapFile::size(), and Kwave::toUint().

Referenced by resize(), and tryToMakePhysical().

491 {
492  Q_ASSERT(new_size);
493  if (!new_size) return false;
494 
495  // check: it must be in physical space, otherwise the rest makes no sense
496  Q_ASSERT(m_unmapped_swap.contains(handle));
497  if (!m_unmapped_swap.contains(handle)) return false;
498  Kwave::SwapFile *swap = m_unmapped_swap[handle];
499  Q_ASSERT(swap);
500  if (!swap) return false;
501 
502  // allocate a new object, including a new handle
503  // if successful it has been stored in m_physical
504  Kwave::Handle temp_handle = allocatePhysical(new_size);
505  if (!temp_handle) return false;
506 
507  physical_memory_t mem = m_physical[temp_handle];
508  Q_ASSERT(mem.m_data);
509  Q_ASSERT(mem.m_size >= new_size);
510 
511  // copy old stuff to new location
512  if (new_size <= swap->size()) {
513  // shrinked
514  swap->read(0, mem.m_data, Kwave::toUint(new_size));
515  } else {
516  // grown
517  swap->read(0, mem.m_data, Kwave::toUint(swap->size()));
518  }
519 
520 #ifdef DEBUG_MEMORY
521  m_stats.swap.unmapped.bytes -= swap->size();
522  m_stats.swap.unmapped.handles--;
523  m_stats.swap.frees++;
524 #endif /* DEBUG_MEMORY */
525 
526  // free the old swapfile
527  m_unmapped_swap.remove(handle);
528  delete swap;
529 
530  // discard the new (temporary) handle and re-use the old one
531  m_physical.remove(temp_handle); // temp_handle is now no longer valid
532  m_physical.insert(handle, mem);
533 
534  // we now have the old data with new size and old handle in m_physical
535 // qDebug("Kwave::MemoryManager[%9d] - reloaded %2u MB from swap",
536 // handle, Kwave::toUint(mem.m_size >> 20));
537 
538  dump("convertToPhysical");
539  return true;
540 }
QHash< Kwave::Handle, Kwave::SwapFile * > m_unmapped_swap
int Handle
Definition: MemoryManager.h:34
int read(unsigned int offset, void *buffer, unsigned int length)
Definition: SwapFile.cpp:258
struct Kwave::MemoryManager::physical_memory_t physical_memory_t
size_t size() const
Definition: SwapFile.h:64
Kwave::Handle allocatePhysical(size_t size)
unsigned int toUint(T x)
Definition: Utils.h:109
Kwave::LRU_Cache< Kwave::Handle, physical_memory_t > m_physical
void dump(const char *function)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ convertToVirtual()

bool Kwave::MemoryManager::convertToVirtual ( Kwave::Handle  handle,
size_t  new_size 
)
protected

convert a physical memory block into a new larger pagefile

Definition at line 445 of file MemoryManager.cpp.

References allocateVirtual(), dump(), free(), Kwave::MemoryManager::physical_memory_t::m_data, m_physical, Kwave::MemoryManager::physical_memory_t::m_size, m_unmapped_swap, Kwave::toUint(), and Kwave::SwapFile::write().

Referenced by freePhysical(), and resize().

447 {
448  // check: it must be in physical space, otherwise the rest makes no sense
449  Q_ASSERT(m_physical.contains(handle));
450  if (!m_physical.contains(handle)) return false;
451 
452  // get the old object in physical memory
453  physical_memory_t mem = m_physical[handle];
454  Q_ASSERT(mem.m_data);
455  Q_ASSERT(mem.m_size);
456  if (!mem.m_data || !mem.m_size) return false;
457 
458  // allocate a new object, including a new handle
459  // if successful it has been stored in m_unmapped_swap
460  Kwave::Handle temp_handle = allocateVirtual(new_size);
461  if (!temp_handle) return false;
462 
463  // copy old stuff to new location
464  Kwave::SwapFile *swap = m_unmapped_swap[temp_handle];
465  Q_ASSERT(swap);
466  swap->write(0, mem.m_data, Kwave::toUint(mem.m_size));
467 
468  // free the old physical memory
469  ::free(mem.m_data);
470  m_physical.remove(handle);
471 #ifdef DEBUG_MEMORY
472  m_stats.physical.handles--;
473  m_stats.physical.frees++;
474  m_stats.physical.bytes -= mem.m_size;
475 #endif /* DEBUG_MEMORY */
476 
477  // discard the new (temporary) handle and re-use the old one
478  m_unmapped_swap.remove(temp_handle); // temp_handle is now no longer valid
479  m_unmapped_swap.insert(handle, swap);
480 
481  // we now have the old data with new size and old handle in m_unmapped_swap
482 // qDebug("Kwave::MemoryManager[%9d] - moved to swap", handle);
483 
484  dump("convertToVirtual");
485  return true;
486 }
QHash< Kwave::Handle, Kwave::SwapFile * > m_unmapped_swap
int write(unsigned int offset, const void *buffer, unsigned int length)
Definition: SwapFile.cpp:274
void free(Kwave::Handle &handle) Q_DECL_EXPORT
int Handle
Definition: MemoryManager.h:34
struct Kwave::MemoryManager::physical_memory_t physical_memory_t
Kwave::Handle allocateVirtual(size_t size)
unsigned int toUint(T x)
Definition: Utils.h:109
Kwave::LRU_Cache< Kwave::Handle, physical_memory_t > m_physical
void dump(const char *function)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ dump()

void Kwave::MemoryManager::dump ( const char *  function)
private

dump current state (for debugging)

Definition at line 1042 of file MemoryManager.cpp.

References m_cached_swap, m_mapped_swap, m_physical, m_unmapped_swap, physicalUsed(), and virtualUsed().

Referenced by allocate(), allocateVirtual(), convertToPhysical(), convertToVirtual(), free(), resize(), and unmapFromCache().

1043 {
1044 #if 0
1045  quint64 v_used = virtualUsed();
1046  quint64 p_used = physicalUsed();
1047 
1048  qDebug("------- %s -------", function);
1049  foreach (const Kwave::Handle &handle, m_physical.keys())
1050  qDebug(" P[%5u]: %5u", static_cast<unsigned int>(handle),
1051  m_physical[handle].m_size >> 20);
1052 
1053  unsigned int m = 0;
1054  foreach (const Kwave::Handle &handle, m_mapped_swap.keys()) {
1055  m += m_mapped_swap[handle]->size() >> 20;
1056  qDebug(" M[%5u]: %5u", static_cast<unsigned int>(handle),
1057  m_mapped_swap[handle]->size() >> 20);
1058  }
1059 
1060  unsigned int c = 0;
1061  foreach (const Kwave::Handle &handle, m_cached_swap.keys()) {
1062  c += m_cached_swap[handle]->size() >> 20;
1063  qDebug(" C[%5u]: %5u", static_cast<unsigned int>(handle),
1064  m_cached_swap[handle]->size() >> 20);
1065  }
1066 
1067  unsigned int u = 0;
1068  foreach (const Kwave::Handle &handle, m_unmapped_swap.keys()) {
1069  u += m_unmapped_swap[handle]->size() >> 20;
1070  qDebug(" U[%5u]: %5u", static_cast<unsigned int>(handle),
1071  m_unmapped_swap[handle]->size() >> 20);
1072  }
1073 
1074  qDebug("physical: %5llu MB, virtual: %5llu MB [m:%5u, c:%5u, u:%5u]",
1075  p_used, v_used, m, c, u);
1076 #endif
1077 
1078 #ifdef DEBUG_MEMORY
1079  qDebug("------- %s -------", function);
1080  qDebug("physical: %12llu, %12llu / %12llu (%12llu : %12llu)",
1081  m_stats.physical.handles,
1082  m_stats.physical.bytes,
1083  m_stats.physical.limit,
1084  m_stats.physical.allocs,
1085  m_stats.physical.frees);
1086  qDebug("mapped swap: %12llu, %12llu / %12llu (%12llu : %12llu)",
1087  m_stats.swap.mapped.handles,
1088  m_stats.swap.mapped.bytes,
1089  m_stats.swap.limit,
1090  m_stats.swap.allocs,
1091  m_stats.swap.frees);
1092  qDebug("cached: %12llu, %12llu",
1093  m_stats.swap.cached.handles,
1094  m_stats.swap.cached.bytes);
1095  qDebug("unmapped: %12llu, %12llu",
1096  m_stats.swap.unmapped.handles,
1097  m_stats.swap.unmapped.bytes);
1098  qDebug("-----------------------------------------------------------------");
1099 
1100 #else /* DEBUG_MEMORY */
1101  Q_UNUSED(function);
1102 #endif /* DEBUG_MEMORY */
1103 }
QHash< Kwave::Handle, Kwave::SwapFile * > m_unmapped_swap
QHash< Kwave::Handle, Kwave::SwapFile * > m_mapped_swap
int Handle
Definition: MemoryManager.h:34
QHash< Kwave::Handle, Kwave::SwapFile * > m_cached_swap
Kwave::LRU_Cache< Kwave::Handle, physical_memory_t > m_physical
Here is the call graph for this function:
Here is the caller graph for this function:

◆ free()

void Kwave::MemoryManager::free ( Kwave::Handle handle)

Frees a block of memory that has been previously allocated with the allocate() function.

Parameters
handlereference to the handle to the block to be freed. The handle will be set to zero afterwards.

Definition at line 717 of file MemoryManager.cpp.

References dump(), m_lock, m_mapped_swap, m_physical, m_unmapped_swap, Kwave::SwapFile::mapCount(), Kwave::SwapFile::size(), unmap(), and unmapFromCache().

Referenced by Kwave::MimeData::Buffer::close(), convertToVirtual(), Kwave::MimeData::Buffer::mapToByteArray(), Kwave::Stripe::resizeStorage(), and Kwave::Stripe::StripeStorage::~StripeStorage().

718 {
719  if (!handle) return;
720  QMutexLocker lock(&m_lock);
721 
722 // qDebug("Kwave::MemoryManager[%9d] - free", handle);
723 
724  if (m_physical.contains(handle)) {
725  // physical memory (must not be mapped)
726  Q_ASSERT(!m_physical[handle].m_mapcount);
727 
728 #ifdef DEBUG_MEMORY
729  m_stats.physical.handles--;
730  m_stats.physical.frees++;
731  m_stats.physical.bytes -= m_physical[handle].m_size;
732 #endif /* DEBUG_MEMORY */
733 
734  void *b = m_physical[handle].m_data;
735  Q_ASSERT(b);
736  m_physical.remove(handle);
737  ::free(b);
738  handle = 0;
739 
740  dump("free");
741  return;
742  }
743 
744  Q_ASSERT(!m_mapped_swap.contains(handle));
745  if (m_mapped_swap.contains(handle)) {
746  // no-good: swapfile is still mapped !?
747  unmap(handle);
748  }
749 
750  unmapFromCache(handle); // make sure it is not in the cache
751 
752  if (m_unmapped_swap.contains(handle)) {
753  // remove the pagefile
754  Kwave::SwapFile *swap = m_unmapped_swap[handle];
755 #ifdef DEBUG_MEMORY
756  m_stats.swap.unmapped.handles--;
757  m_stats.swap.unmapped.bytes -= swap->size();
758  m_stats.swap.frees++;
759 #endif /* DEBUG_MEMORY */
760  m_unmapped_swap.remove(handle);
761  Q_ASSERT(!swap->mapCount());
762  delete swap;
763  handle = 0;
764 
765  dump("free");
766  return;
767  }
768 
769  Q_ASSERT(!handle);
770  handle = 0;
771 }
QHash< Kwave::Handle, Kwave::SwapFile * > m_unmapped_swap
QHash< Kwave::Handle, Kwave::SwapFile * > m_mapped_swap
void free(Kwave::Handle &handle) Q_DECL_EXPORT
void unmapFromCache(Kwave::Handle handle)
size_t size() const
Definition: SwapFile.h:64
void unmap(Kwave::Handle handle) Q_DECL_EXPORT
int mapCount() const
Definition: SwapFile.h:67
Kwave::LRU_Cache< Kwave::Handle, physical_memory_t > m_physical
void dump(const char *function)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ freePhysical()

bool Kwave::MemoryManager::freePhysical ( size_t  size)
private

try to make some room in the physical memory area by kicking out the oldest entries to swap if possible.

Parameters
sizenumber of bytes to free
Returns
true if successful, false if failed

Definition at line 255 of file MemoryManager.cpp.

References convertToVirtual(), Kwave::MemoryManager::physical_memory_t::m_mapcount, m_physical, Kwave::MemoryManager::physical_memory_t::m_size, and Kwave::toUint().

Referenced by allocate(), resize(), and tryToMakePhysical().

256 {
257  size_t freed = 0;
258 
259  if (m_physical.isEmpty()) return false;
260 
261  QList<Kwave::Handle> handles = m_physical.keys();
262  QMutableListIterator<Kwave::Handle> it(handles);
263  it.toBack();
264  while (it.hasPrevious()) {
265  Kwave::Handle handle = it.previous();
266  const physical_memory_t &p = m_physical[handle];
267  if (p.m_mapcount) continue; // in use :-(
268 
269  // convert to swapfile
270  size_t s = p.m_size;
271 #if 0
272  qDebug("Kwave::MemoryManager[%9d] - swapping %2u MB out to make "\
273  "space for %2u MB", handle,
274  Kwave::toUint(s >> 20),
275  Kwave::toUint(size >> 20));
276 #endif
277 
278  if (convertToVirtual(handle, s)) {
279  freed += s;
280  if (freed >= size) return true;
281 
282  // abort if the list is now empty
283  if (m_physical.isEmpty()) return false;
284  }
285  }
286 
287  return false;
288 }
bool convertToVirtual(Kwave::Handle handle, size_t new_size)
int Handle
Definition: MemoryManager.h:34
struct Kwave::MemoryManager::physical_memory_t physical_memory_t
unsigned int toUint(T x)
Definition: Utils.h:109
Kwave::LRU_Cache< Kwave::Handle, physical_memory_t > m_physical
Here is the call graph for this function:
Here is the caller graph for this function:

◆ instance()

◆ map()

void * Kwave::MemoryManager::map ( Kwave::Handle  handle)

Map a portion of memory and return the physical address.

Parameters
handlehandle of the object that identifies the memory block
Returns
pointer to the mapped area or null if failed

Definition at line 774 of file MemoryManager.cpp.

References Kwave::SwapFile::address(), m_cached_swap, m_lock, m_mapped_swap, m_physical, m_unmapped_swap, Kwave::SwapFile::map(), Kwave::SwapFile::mapCount(), Kwave::SwapFile::size(), tryToMakePhysical(), and unmapFromCache().

Referenced by Kwave::Stripe::StripeStorage::map(), Kwave::MimeData::Buffer::mapToByteArray(), and Kwave::Stripe::StripeStorage::StripeStorage().

775 {
776  QMutexLocker lock(&m_lock);
777 
778  Q_ASSERT(handle);
779  if (!handle) return Q_NULLPTR; // object not found ?
780 
781  // try to convert to physical RAM
782  tryToMakePhysical(handle);
783 
784  // simple case: physical memory does not really need to be mapped
785  if (m_physical.contains(handle)) {
786  m_physical[handle].m_mapcount++;
787 // qDebug("Kwave::MemoryManager[%9d] - mmap -> physical", handle);
788  return m_physical[handle].m_data;
789  }
790 
791  // no physical mem -> must be a swapfile
792 
793  // if it is already in the cache -> shortcut !
794  if (m_cached_swap.contains(handle)) {
795  Kwave::SwapFile *swap = m_cached_swap[handle];
796  m_cached_swap.remove(handle);
797  m_mapped_swap.insert(handle, swap);
798 #ifdef DEBUG_MEMORY
799  m_stats.swap.cached.handles--;
800  m_stats.swap.cached.bytes -= swap->size();
801  m_stats.swap.mapped.handles++;
802  m_stats.swap.mapped.bytes += swap->size();
803 #endif /* DEBUG_MEMORY */
804 // qDebug("Kwave::MemoryManager[%9d] - mmap -> cache hit", handle);
805  Q_ASSERT(swap->mapCount() == 1);
806  return swap->address();
807  }
808 
809  // other simple case: already mapped
810  if (m_mapped_swap.contains(handle)) {
811  Kwave::SwapFile *swap = m_mapped_swap[handle];
812  Q_ASSERT(swap->mapCount() >= 1);
813 // qDebug("Kwave::MemoryManager[%9d] - mmap -> recursive(%d)",
814 // handle, swap->mapCount());
815  return swap->map(); // increase map count to 2...
816  }
817 
818  // more complicated case: unmapped swapfile
819  if (m_unmapped_swap.contains(handle)) {
820  // map it into memory
821  Kwave::SwapFile *swap = m_unmapped_swap[handle];
822  Q_ASSERT(!swap->mapCount());
823  void *mapped = swap->map();
824  if (!mapped) {
825  qDebug("Kwave::MemoryManager[%9d] - mmap FAILED", handle);
826  // maybe address space is already full wil already cached
827  // mapped swap files -> kick out the last one and try again
828  while (!mapped && !m_cached_swap.isEmpty()) {
829  Kwave::Handle h = m_cached_swap.keys().last();
830  unmapFromCache(h);
831  mapped = swap->map();
832  qDebug("Kwave::MemoryManager[%9d] - retry: %p", handle, mapped);
833  }
834 
835  if (!mapped) return Q_NULLPTR;
836  }
837 
838  // remember that we have mapped it, move the entry from the
839  // "unmapped_swap" to the "mapped_swap" list
840  m_unmapped_swap.remove(handle);
841  m_mapped_swap.insert(handle, swap);
842 
843 #ifdef DEBUG_MEMORY
844  m_stats.swap.unmapped.handles--;
845  m_stats.swap.unmapped.bytes -= swap->size();
846  m_stats.swap.mapped.handles++;
847  m_stats.swap.mapped.bytes += swap->size();
848 #endif /* DEBUG_MEMORY */
849 // qDebug("Kwave::MemoryManager[%9d] - mmap -> new mapping", handle);
850  return mapped;
851  } else {
852  Q_ASSERT(m_unmapped_swap.contains(handle));
853  }
854 
855  // nothing known about this object !?
856  return Q_NULLPTR;
857 }
QHash< Kwave::Handle, Kwave::SwapFile * > m_unmapped_swap
void * map()
Definition: SwapFile.cpp:206
void * address() const
Definition: SwapFile.h:58
QHash< Kwave::Handle, Kwave::SwapFile * > m_mapped_swap
void tryToMakePhysical(Kwave::Handle handle)
void unmapFromCache(Kwave::Handle handle)
int Handle
Definition: MemoryManager.h:34
QHash< Kwave::Handle, Kwave::SwapFile * > m_cached_swap
size_t size() const
Definition: SwapFile.h:64
int mapCount() const
Definition: SwapFile.h:67
Kwave::LRU_Cache< Kwave::Handle, physical_memory_t > m_physical
Here is the call graph for this function:
Here is the caller graph for this function:

◆ newHandle()

Kwave::Handle Kwave::MemoryManager::newHandle ( )
private

get a new handle.

Note
the handle does not need to be freed later
Returns
a non-zero handle or zero if all handles are in use

Definition at line 228 of file MemoryManager.cpp.

References m_cached_swap, m_last_handle, m_mapped_swap, m_physical, and m_unmapped_swap.

Referenced by allocatePhysical(), and allocateVirtual().

229 {
230  for (unsigned int i = 0; i < INT_MAX; i++) {
231  // increment to get the next handle
232  m_last_handle++;
233 
234  // allow only non-zero positive values (handle wraparound)
235  if (m_last_handle <= 0) {
236  m_last_handle = 0;
237  continue;
238  }
239 
240  // if handle is in use -> next one please...
241  if (m_physical.contains(m_last_handle)) continue;
242  if (m_mapped_swap.contains(m_last_handle)) continue;
243  if (m_unmapped_swap.contains(m_last_handle)) continue;
244  if (m_cached_swap.contains(m_last_handle)) continue;
245 
246  // valid number and not in use -> found a new one :-)
247  return m_last_handle;
248  }
249 
250  // if we reach this point all handles are in use :-(
251  return 0;
252 }
QHash< Kwave::Handle, Kwave::SwapFile * > m_unmapped_swap
QHash< Kwave::Handle, Kwave::SwapFile * > m_mapped_swap
QHash< Kwave::Handle, Kwave::SwapFile * > m_cached_swap
static Kwave::Handle m_last_handle
Kwave::LRU_Cache< Kwave::Handle, physical_memory_t > m_physical
Here is the caller graph for this function:

◆ nextSwapFileName()

QString Kwave::MemoryManager::nextSwapFileName ( Kwave::Handle  handle)
protected

returns a new swap file name

Definition at line 381 of file MemoryManager.cpp.

References _, and m_swap_dir.

Referenced by allocateVirtual().

382 {
383  QFileInfo file;
384  QString filename;
385 
386  // these 6 'X' chars are needed for mkstemp !
387  filename = _("kwave-swapfile-%1-XXXXXX");
388  filename = filename.arg(static_cast<unsigned int>(handle),
389  10, 10, QLatin1Char('0'));
390 
391  file.setFile(m_swap_dir, filename);
392  return file.absoluteFilePath();
393 }
#define _(m)
Definition: memcpy.c:66
Here is the caller graph for this function:

◆ physicalUsed()

quint64 Kwave::MemoryManager::physicalUsed ( )
protected

returns the currently allocated physical memory

Definition at line 355 of file MemoryManager.cpp.

References m_physical, and Kwave::MemoryManager::physical_memory_t::m_size.

Referenced by allocatePhysical(), dump(), resize(), and tryToMakePhysical().

356 {
357  quint64 used = 0;
358  foreach (const physical_memory_t &mem, m_physical.values())
359  used += (mem.m_size >> 10) + 1;
360  return (used >> 10);
361 }
struct Kwave::MemoryManager::physical_memory_t physical_memory_t
Kwave::LRU_Cache< Kwave::Handle, physical_memory_t > m_physical
Here is the caller graph for this function:

◆ readFrom()

int Kwave::MemoryManager::readFrom ( Kwave::Handle  handle,
unsigned int  offset,
void *  buffer,
unsigned int  length 
)

Read from a memory block into a buffer

Parameters
handlehandle of the object that identifies the memory block
offsetoffset within the object [bytes]
bufferpointer to a buffer that is to be filled
lengthnumber of bytes to read
Returns
number of read bytes or < 0 if failed

Definition at line 941 of file MemoryManager.cpp.

References Kwave::SwapFile::address(), m_cached_swap, m_lock, m_mapped_swap, m_physical, m_unmapped_swap, Kwave::SwapFile::mapCount(), MEMCPY, Kwave::SwapFile::read(), and tryToMakePhysical().

Referenced by Kwave::Stripe::read(), Kwave::MimeData::Buffer::readData(), and Kwave::Stripe::StripeStorage::StripeStorage().

943 {
944  QMutexLocker lock(&m_lock);
945 
946  if (!handle) return 0;
947 
948  // try to convert to physical RAM
949  tryToMakePhysical(handle);
950 
951  // simple case: physical memory -> memcpy(...)
952  if (m_physical.contains(handle)) {
953 // qDebug("Kwave::MemoryManager[%9d] - readFrom -> physical", handle);
954  char *data = reinterpret_cast<char *>(m_physical[handle].m_data);
955  MEMCPY(buffer, data + offset, length);
956  return length;
957  }
958 
959  // no physical mem -> must be a swapfile
960 
961  // still in the cache and mapped -> memcpy(...)
962  if (m_cached_swap.contains(handle)) {
963  Kwave::SwapFile *swap = m_cached_swap[handle];
964  Q_ASSERT(swap->mapCount() == 1);
965  char *data = reinterpret_cast<char *>(swap->address());
966  Q_ASSERT(data);
967  if (!data) return 0;
968  MEMCPY(buffer, data + offset, length);
969 // qDebug("Kwave::MemoryManager[%9d] - readFrom -> cached swap", handle);
970  return length;
971  }
972 
973  // currently mmapped -> memcpy(...)
974  if (m_mapped_swap.contains(handle)) {
975  Kwave::SwapFile *swap = m_mapped_swap[handle];
976  Q_ASSERT(swap->mapCount() >= 1);
977  char *data = reinterpret_cast<char *>(swap->address());
978  Q_ASSERT(data);
979  if (!data) return 0;
980  MEMCPY(buffer, data + offset, length);
981 // qDebug("Kwave::MemoryManager[%9d] - readFrom -> mapped swap", handle);
982  return length;
983  }
984 
985  // now it must be in unmapped swap -> read(...)
986  Q_ASSERT(m_unmapped_swap.contains(handle));
987  if (m_unmapped_swap.contains(handle)) {
988 // qDebug("Kwave::MemoryManager[%9d] - readFrom -> unmapped swap", handle);
989  Kwave::SwapFile *swap = m_unmapped_swap[handle];
990  length = swap->read(offset, buffer, length);
991  return length;
992  }
993 
994  return 0;
995 }
QHash< Kwave::Handle, Kwave::SwapFile * > m_unmapped_swap
void * address() const
Definition: SwapFile.h:58
QHash< Kwave::Handle, Kwave::SwapFile * > m_mapped_swap
void tryToMakePhysical(Kwave::Handle handle)
int read(unsigned int offset, void *buffer, unsigned int length)
Definition: SwapFile.cpp:258
#define MEMCPY
Definition: memcpy.h:37
QHash< Kwave::Handle, Kwave::SwapFile * > m_cached_swap
int mapCount() const
Definition: SwapFile.h:67
Kwave::LRU_Cache< Kwave::Handle, physical_memory_t > m_physical
Here is the call graph for this function:
Here is the caller graph for this function:

◆ resize()

bool Kwave::MemoryManager::resize ( Kwave::Handle  handle,
size_t  size 
)

Resizes a block of memory to a new size. If the block will no longer fit in physical memory, the block will be swapped out to a page file.

Parameters
handlehandle of the existing block
sizenew size of the block in bytes
Returns
true if successful, false if out of memory or if the block is currently in use

Definition at line 575 of file MemoryManager.cpp.

References convertToPhysical(), convertToVirtual(), dump(), freePhysical(), Kwave::MemoryManager::physical_memory_t::m_data, m_lock, Kwave::MemoryManager::physical_memory_t::m_mapcount, m_mapped_swap, m_physical, m_physical_limit, Kwave::MemoryManager::physical_memory_t::m_size, m_unmapped_swap, m_virtual_limit, physicalUsed(), Kwave::SwapFile::resize(), Kwave::SwapFile::size(), Kwave::toUint(), and unmapFromCache().

Referenced by Kwave::MimeData::Buffer::writeData().

576 {
577  QMutexLocker lock(&m_lock);
578 
579 // qDebug("Kwave::MemoryManager[%9d] - resize to %u", handle,
580 // Kwave::toUint(size));
581 
582  // case 1: physical memory
583  if (m_physical.contains(handle)) {
584  const physical_memory_t phys_c = m_physical[handle];
585 
586  // check: it must not be mmapped!
587  Q_ASSERT(!phys_c.m_mapcount);
588  if (phys_c.m_mapcount) return false;
589 
590  // if we are increasing: check if we get too large
591  size_t current_size = phys_c.m_size;
592  if ((size > current_size) && (physicalUsed() +
593  ((size - current_size) >> 20) > m_physical_limit))
594  {
595  // first try to swap out some old stuff
596  m_physical[handle].m_mapcount++;
597  bool physical_freed = freePhysical(size);
598  m_physical[handle].m_mapcount--;
599 
600  if (!physical_freed) {
601  // still too large -> move to virtual memory
602  if (m_virtual_limit) {
603  qDebug("Kwave::MemoryManager[%9d] - resize(%uMB) "
604  "-> moving to swap",
605  handle, Kwave::toUint(size >> 20));
606  return convertToVirtual(handle, size);
607  } else {
608  qDebug("Kwave::MemoryManager[%9d] - resize(%uMB) "
609  "-> OOM", handle, Kwave::toUint(size >> 20));
610  return false;
611  }
612  }
613  }
614 
615  // try to resize the physical memory
616  physical_memory_t phys = m_physical[handle];
617  void *old_block = phys.m_data;
618  void *new_block = ::realloc(old_block, size);
619  if (new_block) {
620  phys.m_data = new_block;
621  phys.m_size = size;
622  phys.m_mapcount = 0;
623  m_physical[handle] = phys;
624 #ifdef DEBUG_MEMORY
625  m_stats.physical.bytes -= current_size;
626  m_stats.physical.bytes += size;
627 #endif /* DEBUG_MEMORY */
628 
629  dump("resize");
630  return true;
631  } else {
632  // resizing failed, try to allocate virtual memory for it
633  return convertToVirtual(handle, size);
634  }
635  }
636 
637  // case 2: mapped swapfile in cache -> unmap !
638  unmapFromCache(handle); // make sure it is not in the cache
639 
640  // case 3: mapped swapfile -> forbidden !
641  Q_ASSERT(!m_mapped_swap.contains(handle));
642  if (m_mapped_swap.contains(handle))
643  return false;
644 
645  // case 4: unmapped swapfile -> resize
646  Q_ASSERT(m_unmapped_swap.contains(handle));
647  if (m_unmapped_swap.contains(handle)) {
648 
649  // try to find space in the physical memory
650  if ((physicalUsed() + (size >> 20) > m_physical_limit)) {
651  // free some space if necessary
652  if (freePhysical(size)) {
653  if (convertToPhysical(handle, size)) return true;
654  }
655  } else {
656  // try to convert into the currently available phys. RAM
657  if (convertToPhysical(handle, size)) return true;
658  }
659 
660  // not enough free RAM: resize the pagefile
661 // qDebug("Kwave::MemoryManager[%9d] - resize swap %u -> %u MB",
662 // handle,
663 // Kwave::toUint(swap->size() >> 20),
664 // Kwave::toUint(size >> 20));
665 
666  dump("resize");
667  Kwave::SwapFile *swap = m_unmapped_swap[handle];
668 #ifdef DEBUG_MEMORY
669  size_t old_size = swap->size();
670 #endif /* DEBUG_MEMORY */
671  bool ok = swap->resize(size);
672  if (!ok) return false;
673 #ifdef DEBUG_MEMORY
674  m_stats.swap.unmapped.bytes -= old_size;
675  m_stats.swap.unmapped.bytes += size;
676 #endif /* DEBUG_MEMORY */
677  return true;
678  }
679 
680  return false; // nothing known about this object / invalid handle?
681 }
QHash< Kwave::Handle, Kwave::SwapFile * > m_unmapped_swap
bool convertToVirtual(Kwave::Handle handle, size_t new_size)
bool convertToPhysical(Kwave::Handle handle, size_t new_size)
bool freePhysical(size_t size)
QHash< Kwave::Handle, Kwave::SwapFile * > m_mapped_swap
void unmapFromCache(Kwave::Handle handle)
struct Kwave::MemoryManager::physical_memory_t physical_memory_t
size_t size() const
Definition: SwapFile.h:64
bool resize(size_t size)
Definition: SwapFile.cpp:122
unsigned int toUint(T x)
Definition: Utils.h:109
Kwave::LRU_Cache< Kwave::Handle, physical_memory_t > m_physical
void dump(const char *function)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ setPhysicalLimit()

void Kwave::MemoryManager::setPhysicalLimit ( quint64  mb)

Sets the limit of physical memory that can be used.

Parameters
mbnumber of whole megabytes of the limit

Definition at line 171 of file MemoryManager.cpp.

References m_lock, m_physical_limit, and totalPhysical().

Referenced by Kwave::MemoryPlugin::applySettings().

172 {
173  QMutexLocker lock(&m_lock);
174 
175  m_physical_limit = mb;
176  mb = totalPhysical();
177  if (m_physical_limit > mb) m_physical_limit = mb;
178 #ifdef DEBUG_MEMORY
179  m_stats.physical.limit = m_physical_limit << 20ULL;
180 #endif /* DEBUG_MEMORY */
181 }
quint64 totalPhysical() Q_DECL_EXPORT
Here is the call graph for this function:
Here is the caller graph for this function:

◆ setSwapDirectory()

void Kwave::MemoryManager::setSwapDirectory ( const QString &  dir)

Sets the directory where swap files should be stored

Parameters
dirdirectory

Definition at line 199 of file MemoryManager.cpp.

References m_lock, and m_swap_dir.

Referenced by Kwave::MemoryPlugin::applySettings().

200 {
201  QMutexLocker lock(&m_lock);
202  m_swap_dir = dir;
203 }
Here is the caller graph for this function:

◆ setUndoLimit()

void Kwave::MemoryManager::setUndoLimit ( quint64  mb)

Sets the limit of memory that can be used for undo/redo.

Parameters
mbnumber of whole megabytes of the limit

Definition at line 206 of file MemoryManager.cpp.

References m_lock, m_undo_limit, and totalPhysical().

Referenced by Kwave::MemoryPlugin::applySettings().

207 {
208  QMutexLocker lock(&m_lock);
209 
210  m_undo_limit = mb;
211  mb = totalPhysical();
212  if (m_undo_limit > mb) m_undo_limit = mb;
213 }
quint64 totalPhysical() Q_DECL_EXPORT
Here is the call graph for this function:
Here is the caller graph for this function:

◆ setVirtualLimit()

void Kwave::MemoryManager::setVirtualLimit ( quint64  mb)

Sets the limit of virtual memory that can be used.

Parameters
mbnumber of whole megabytes of the limit
Todo:
write a function to find out the limit of virtual memory

Definition at line 184 of file MemoryManager.cpp.

References m_lock, and m_virtual_limit.

Referenced by Kwave::MemoryPlugin::applySettings().

185 {
186  QMutexLocker lock(&m_lock);
187 
188  m_virtual_limit = mb;
189 #ifdef DEBUG_MEMORY
190  m_stats.swap.limit = m_virtual_limit << 20ULL;
191 #endif /* DEBUG_MEMORY */
192 
194 // mb = totalVirtual();
195 // if (m_virtual_limit > mb) m_virtual_limit = mb;
196 }
Here is the caller graph for this function:

◆ sizeOf()

size_t Kwave::MemoryManager::sizeOf ( Kwave::Handle  handle)

Returns the allocated size of the block

Note
this may be more than allocated, can be rounded up

Definition at line 684 of file MemoryManager.cpp.

References m_cached_swap, m_lock, m_mapped_swap, m_physical, Kwave::MemoryManager::physical_memory_t::m_size, m_unmapped_swap, and Kwave::SwapFile::size().

Referenced by Kwave::MimeData::Buffer::writeData().

685 {
686  if (!handle) return 0;
687  QMutexLocker lock(&m_lock);
688 
689  // case 1: physical memory
690  if (m_physical.contains(handle)) {
691  const physical_memory_t phys_c = m_physical[handle];
692  return phys_c.m_size;
693  }
694 
695  // case 2: cached mapped swapfile
696  if (m_cached_swap.contains(handle)) {
697  const Kwave::SwapFile *swapfile = m_cached_swap[handle];
698  return swapfile->size();
699  }
700 
701  // case 3: mapped swapfile
702  if (m_mapped_swap.contains(handle)) {
703  const Kwave::SwapFile *swapfile = m_mapped_swap[handle];
704  return swapfile->size();
705  }
706 
707  // case 4: unmapped swapfile
708  if (m_unmapped_swap.contains(handle)) {
709  const Kwave::SwapFile *swapfile = m_unmapped_swap[handle];
710  return swapfile->size();
711  }
712 
713  return 0;
714 }
QHash< Kwave::Handle, Kwave::SwapFile * > m_unmapped_swap
QHash< Kwave::Handle, Kwave::SwapFile * > m_mapped_swap
QHash< Kwave::Handle, Kwave::SwapFile * > m_cached_swap
struct Kwave::MemoryManager::physical_memory_t physical_memory_t
size_t size() const
Definition: SwapFile.h:64
Kwave::LRU_Cache< Kwave::Handle, physical_memory_t > m_physical
Here is the call graph for this function:
Here is the caller graph for this function:

◆ totalPhysical()

quint64 Kwave::MemoryManager::totalPhysical ( )

Returns the total amount of theoretically available physical memory, as the minimum of the totally installed memory and ulimit settings.

Definition at line 222 of file MemoryManager.cpp.

References m_physical_max.

Referenced by allocatePhysical(), Kwave::MemoryDialog::MemoryDialog(), setPhysicalLimit(), setUndoLimit(), and tryToMakePhysical().

223 {
224  return m_physical_max;
225 }
Here is the caller graph for this function:

◆ tryToMakePhysical()

void Kwave::MemoryManager::tryToMakePhysical ( Kwave::Handle  handle)
protected

tries to convert to physical RAM

Definition at line 543 of file MemoryManager.cpp.

References convertToPhysical(), freePhysical(), m_cached_swap, m_mapped_swap, m_physical, m_physical_limit, m_unmapped_swap, physicalUsed(), Kwave::SwapFile::size(), and totalPhysical().

Referenced by map(), readFrom(), and writeTo().

544 {
545  if (!handle) return;
546  if (m_physical.contains(handle)) return; // already ok
547  if (m_mapped_swap.contains(handle)) return; // not allowed
548  if (m_cached_swap.contains(handle)) return; // already fast enough
549 
550  Q_ASSERT(m_unmapped_swap.contains(handle));
551  if (!m_unmapped_swap.contains(handle)) return;
552 
553  const Kwave::SwapFile *swap = m_unmapped_swap[handle];
554  Q_ASSERT(swap);
555  if (!swap) return;
556 
557  size_t size = swap->size();
558 
559  quint64 limit = totalPhysical();
560  if (m_physical_limit < limit) limit = m_physical_limit;
561  quint64 used = physicalUsed();
562  quint64 available = (used < limit) ? (limit - used) : 0;
563 
564  // if we would go over the physical limit...
565  if ((size >> 20) >= available) {
566  // ...try to swap out some old stuff
567  if (!freePhysical(size)) return;
568  }
569 
570  // try to convert the swapfile back to physical RAM
571  convertToPhysical(handle, size);
572 }
QHash< Kwave::Handle, Kwave::SwapFile * > m_unmapped_swap
quint64 totalPhysical() Q_DECL_EXPORT
bool convertToPhysical(Kwave::Handle handle, size_t new_size)
bool freePhysical(size_t size)
QHash< Kwave::Handle, Kwave::SwapFile * > m_mapped_swap
QHash< Kwave::Handle, Kwave::SwapFile * > m_cached_swap
size_t size() const
Definition: SwapFile.h:64
Kwave::LRU_Cache< Kwave::Handle, physical_memory_t > m_physical
Here is the call graph for this function:
Here is the caller graph for this function:

◆ undoLimit()

quint64 Kwave::MemoryManager::undoLimit ( ) const

Returns the limit of memory that can be used for undo/redo in units of whole megabytes

Definition at line 216 of file MemoryManager.cpp.

References m_undo_limit.

Referenced by Kwave::SignalManager::freeUndoMemory(), Kwave::SignalManager::redo(), Kwave::SignalManager::registerUndoAction(), and Kwave::SignalManager::undo().

217 {
218  return m_undo_limit;
219 }
Here is the caller graph for this function:

◆ unmap()

void Kwave::MemoryManager::unmap ( Kwave::Handle  handle)

Unmap a memory area, previously mapped with map()

Parameters
handlehandle of a mapped block mapped with map()

Definition at line 882 of file MemoryManager.cpp.

References CACHE_SIZE, m_cached_swap, m_lock, m_mapped_swap, m_physical, m_unmapped_swap, Kwave::SwapFile::mapCount(), Kwave::SwapFile::size(), Kwave::SwapFile::unmap(), and unmapFromCache().

Referenced by Kwave::MimeData::Buffer::close(), free(), Kwave::Stripe::StripeStorage::StripeStorage(), and Kwave::Stripe::StripeStorage::unmap().

883 {
884  QMutexLocker lock(&m_lock);
885 
886  // simple case: physical memory does not really need to be unmapped
887  if (m_physical.contains(handle)) {
888 // qDebug("Kwave::MemoryManager[%9d] - unmap -> physical", handle);
889  Q_ASSERT(m_physical[handle].m_mapcount);
890  if (m_physical[handle].m_mapcount)
891  m_physical[handle].m_mapcount--;
892  return;
893  }
894 
895 // qDebug("Kwave::MemoryManager[%9d] - unmap swap", handle);
896 
897  // just to be sure: should also not be in cache!
898  Q_ASSERT(!m_cached_swap.contains(handle));
899  unmapFromCache(handle);
900 
901  // unmapped swapfile: already unmapped !?
902  if (m_unmapped_swap.contains(handle)) {
903  Q_ASSERT(!m_unmapped_swap.contains(handle));
904  return; // nothing to do
905  }
906 
907  // must be a mapped swapfile: move it into the cache
908  Q_ASSERT(m_mapped_swap.contains(handle));
909  if (m_mapped_swap.contains(handle)) {
910  Kwave::SwapFile *swap = m_mapped_swap[handle];
911  Q_ASSERT(swap->mapCount());
912  if (swap->mapCount() > 1) {
913  // only unmap and internally reduce the map count
914  swap->unmap();
915 // qDebug("Kwave::MemoryManager[%9d] - unmap -> recursive(%d)",
916 // handle, swap->mapCount());
917  } else if (swap->mapCount() == 1) {
918  // move to cache instead of really unmapping
919 
920  // make room in the cache if necessary
921  while (m_cached_swap.count() >= CACHE_SIZE) {
922  unmapFromCache(m_cached_swap.keys().first());
923  }
924 
925  // move it into the swap file cache
926  m_mapped_swap.remove(handle);
927  m_cached_swap.insert(handle, swap);
928 #ifdef DEBUG_MEMORY
929  m_stats.swap.mapped.handles--;
930  m_stats.swap.mapped.bytes -= swap->size();
931  m_stats.swap.cached.handles++;
932  m_stats.swap.cached.bytes += swap->size();
933 #endif /* DEBUG_MEMORY */
934 // qDebug("Kwave::MemoryManager[%9d] - unmap -> moved to cache",
935 // handle);
936  }
937  }
938 }
QHash< Kwave::Handle, Kwave::SwapFile * > m_unmapped_swap
QHash< Kwave::Handle, Kwave::SwapFile * > m_mapped_swap
void unmapFromCache(Kwave::Handle handle)
QHash< Kwave::Handle, Kwave::SwapFile * > m_cached_swap
size_t size() const
Definition: SwapFile.h:64
#define CACHE_SIZE
int mapCount() const
Definition: SwapFile.h:67
Kwave::LRU_Cache< Kwave::Handle, physical_memory_t > m_physical
Here is the call graph for this function:
Here is the caller graph for this function:

◆ unmapFromCache()

void Kwave::MemoryManager::unmapFromCache ( Kwave::Handle  handle)
private

Makes sure that the object is not a swapfile in cache. If so, it will be unmapped and moved to the m_unmapped_swap list.

Parameters
handlehandle of a block in m_cached_swap

Definition at line 860 of file MemoryManager.cpp.

References dump(), m_cached_swap, m_unmapped_swap, Kwave::SwapFile::mapCount(), Kwave::SwapFile::size(), and Kwave::SwapFile::unmap().

Referenced by free(), map(), resize(), unmap(), and writeTo().

861 {
862  if (m_cached_swap.contains(handle)) {
863 // qDebug("Kwave::MemoryManager[%9d] - unmapFromCache", handle);
864  Kwave::SwapFile *swap = m_cached_swap[handle];
865  Q_ASSERT(swap->mapCount() == 1);
866  swap->unmap();
867  Q_ASSERT(!swap->mapCount());
868  m_cached_swap.remove(handle);
869  m_unmapped_swap.insert(handle, swap);
870 #ifdef DEBUG_MEMORY
871  m_stats.swap.cached.handles--;
872  m_stats.swap.cached.bytes -= swap->size();
873  m_stats.swap.unmapped.handles++;
874  m_stats.swap.unmapped.bytes += swap->size();
875 #endif /* DEBUG_MEMORY */
876  }
877 
878  dump("unmap");
879 }
QHash< Kwave::Handle, Kwave::SwapFile * > m_unmapped_swap
QHash< Kwave::Handle, Kwave::SwapFile * > m_cached_swap
size_t size() const
Definition: SwapFile.h:64
int mapCount() const
Definition: SwapFile.h:67
void dump(const char *function)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ virtualUsed()

quint64 Kwave::MemoryManager::virtualUsed ( )
protected

returns the currently allocated virtual memory

Definition at line 364 of file MemoryManager.cpp.

References m_cached_swap, m_mapped_swap, m_unmapped_swap, and Kwave::SwapFile::size().

Referenced by allocateVirtual(), and dump().

365 {
366  quint64 used = 0;
367 
368  foreach (const Kwave::SwapFile *swapfile, m_cached_swap.values())
369  used += (swapfile->size() >> 10) + 1;
370 
371  foreach (const Kwave::SwapFile *swapfile, m_mapped_swap.values())
372  used += (swapfile->size() >> 10) + 1;
373 
374  foreach (const Kwave::SwapFile *swapfile, m_unmapped_swap.values())
375  used += (swapfile->size() >> 10) + 1;
376 
377  return (used >> 10);
378 }
QHash< Kwave::Handle, Kwave::SwapFile * > m_unmapped_swap
QHash< Kwave::Handle, Kwave::SwapFile * > m_mapped_swap
QHash< Kwave::Handle, Kwave::SwapFile * > m_cached_swap
size_t size() const
Definition: SwapFile.h:64
Here is the call graph for this function:
Here is the caller graph for this function:

◆ writeTo()

int Kwave::MemoryManager::writeTo ( Kwave::Handle  handle,
unsigned int  offset,
const void *  buffer,
unsigned int  length 
)

Write a buffer into a memory block

Parameters
handlehandle of the object that identifies the memory block
offsetoffset within the object [bytes]
bufferpointer to a buffer that is to be written
lengthnumber of bytes to write
Returns
number of written bytes or < 0 if failed

Definition at line 998 of file MemoryManager.cpp.

References Kwave::MemoryManager::physical_memory_t::m_data, m_lock, m_mapped_swap, m_physical, Kwave::MemoryManager::physical_memory_t::m_size, m_unmapped_swap, MEMCPY, tryToMakePhysical(), unmapFromCache(), and Kwave::SwapFile::write().

Referenced by Kwave::Stripe::append(), Kwave::Stripe::overwrite(), Kwave::Stripe::StripeStorage::StripeStorage(), and Kwave::MimeData::Buffer::writeData().

1000 {
1001  QMutexLocker lock(&m_lock);
1002 
1003  if (!handle) return 0;
1004 
1005  // try to convert to physical RAM
1006  tryToMakePhysical(handle);
1007 
1008  // simple case: memcpy to physical memory
1009  if (m_physical.contains(handle)) {
1010  physical_memory_t &mem = m_physical[handle];
1011 // qDebug("Kwave::MemoryManager[%9d] - writeTo -> physical", handle);
1012  char *data = reinterpret_cast<char *>(mem.m_data);
1013  Q_ASSERT(length <= mem.m_size);
1014  Q_ASSERT(offset < mem.m_size);
1015  Q_ASSERT(offset + length <= mem.m_size);
1016  MEMCPY(data + offset, buffer, length);
1017  return length;
1018  }
1019 
1020  // make sure it's not mmapped
1021  unmapFromCache(handle);
1022 
1023  // writing to mapped swap is not allowed
1024  Q_ASSERT(!m_mapped_swap.contains(handle));
1025  if (m_mapped_swap.contains(handle)) {
1026  return 0;
1027  }
1028 
1029  // now it must be in unmapped swap
1030  Q_ASSERT(m_unmapped_swap.contains(handle));
1031  if (m_unmapped_swap.contains(handle)) {
1032 // qDebug("Kwave::MemoryManager[%9d] - writeTo -> unmapped swap", handle);
1033  Kwave::SwapFile *swap = m_unmapped_swap[handle];
1034  swap->write(offset, buffer, length);
1035  return length;
1036  }
1037 
1038  return 0;
1039 }
QHash< Kwave::Handle, Kwave::SwapFile * > m_unmapped_swap
int write(unsigned int offset, const void *buffer, unsigned int length)
Definition: SwapFile.cpp:274
QHash< Kwave::Handle, Kwave::SwapFile * > m_mapped_swap
void tryToMakePhysical(Kwave::Handle handle)
void unmapFromCache(Kwave::Handle handle)
#define MEMCPY
Definition: memcpy.h:37
struct Kwave::MemoryManager::physical_memory_t physical_memory_t
Kwave::LRU_Cache< Kwave::Handle, physical_memory_t > m_physical
Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ m_cached_swap

QHash<Kwave::Handle, Kwave::SwapFile *> Kwave::MemoryManager::m_cached_swap
private

cache for swapfiles that have been recently used, are mapped and get unmapped if the queue is full. The queue will be used as a FIFO with fixed size.

Definition at line 308 of file MemoryManager.h.

Referenced by close(), dump(), map(), newHandle(), readFrom(), sizeOf(), tryToMakePhysical(), unmap(), unmapFromCache(), and virtualUsed().

◆ m_last_handle

Kwave::Handle Kwave::MemoryManager::m_last_handle = 0
staticprivate

last used handle

Definition at line 314 of file MemoryManager.h.

Referenced by newHandle().

◆ m_lock

QMutex Kwave::MemoryManager::m_lock
private

mutex for ensuring exclusive access

Definition at line 311 of file MemoryManager.h.

Referenced by allocate(), close(), free(), map(), readFrom(), resize(), setPhysicalLimit(), setSwapDirectory(), setUndoLimit(), setVirtualLimit(), sizeOf(), unmap(), and writeTo().

◆ m_mapped_swap

QHash<Kwave::Handle, Kwave::SwapFile *> Kwave::MemoryManager::m_mapped_swap
private

map of swapfile objects that are already mapped into memory

Definition at line 301 of file MemoryManager.h.

Referenced by close(), dump(), free(), map(), newHandle(), readFrom(), resize(), sizeOf(), tryToMakePhysical(), unmap(), virtualUsed(), and writeTo().

◆ m_physical

◆ m_physical_limit

quint64 Kwave::MemoryManager::m_physical_limit
private

limit of the physical memory

Definition at line 280 of file MemoryManager.h.

Referenced by allocatePhysical(), MemoryManager(), resize(), setPhysicalLimit(), and tryToMakePhysical().

◆ m_physical_max

quint64 Kwave::MemoryManager::m_physical_max
private

total maximum physical memory (system dependent)

Definition at line 283 of file MemoryManager.h.

Referenced by MemoryManager(), and totalPhysical().

◆ m_swap_dir

QDir Kwave::MemoryManager::m_swap_dir
private

path where to store swap files

Definition at line 289 of file MemoryManager.h.

Referenced by nextSwapFileName(), and setSwapDirectory().

◆ m_undo_limit

quint64 Kwave::MemoryManager::m_undo_limit
private

limit of memory available for undo/redo

Definition at line 292 of file MemoryManager.h.

Referenced by setUndoLimit(), and undoLimit().

◆ m_unmapped_swap

QHash<Kwave::Handle, Kwave::SwapFile *> Kwave::MemoryManager::m_unmapped_swap
private

map of swapfile objects that are not mapped into memory

Definition at line 298 of file MemoryManager.h.

Referenced by allocateVirtual(), close(), convertToPhysical(), convertToVirtual(), dump(), free(), map(), newHandle(), readFrom(), resize(), sizeOf(), tryToMakePhysical(), unmap(), unmapFromCache(), virtualUsed(), and writeTo().

◆ m_virtual_limit

quint64 Kwave::MemoryManager::m_virtual_limit
private

limit of the virtual memory, 0 = disabled

Definition at line 286 of file MemoryManager.h.

Referenced by allocateVirtual(), MemoryManager(), resize(), and setVirtualLimit().


The documentation for this class was generated from the following files: