22 #include <sys/types.h> 27 #include <QLatin1Char> 28 #include <QMutexLocker> 32 #include <linux/kernel.h> 33 #include <sys/sysinfo.h> 37 #include <sys/resource.h> 57 :m_physical_limit(0), m_physical_max(0), m_virtual_limit(0),
58 m_swap_dir(
_(
"/tmp")), m_undo_limit(0),
59 m_physical(), m_unmapped_swap(), m_mapped_swap(),
60 m_cached_swap(), m_lock()
64 memset(&m_stats, 0x00,
sizeof(m_stats));
72 quint64 total = (1ULL << ((
sizeof(
void *) * 8ULL) - 22ULL));
75 if (total > (1ULL << 32)) total = (1ULL << 32) - 1;
77 qDebug(
"Kwave::MemoryManager: theoretical limit: %llu MB", total);
82 quint64 installed_physical;
88 #ifdef HAVE_SYSINFO_MEMUNIT 89 installed_physical = (info.totalram * info.mem_unit) >> 20;
91 qDebug(
"Kwave::MemoryManager: sysinfo/memunit: %llu MB", installed_physical);
94 installed_physical = info.totalram >> 20;
95 qDebug(
"Kwave::MemoryManager: sysinfo: %llu MB", installed_physical);
97 if (installed_physical && (installed_physical < total))
98 total = installed_physical;
101 #ifdef HAVE_GETRLIMIT 105 if (getrlimit(RLIMIT_DATA, &limit) == 0) {
106 quint64 physical_ulimit =
107 qMin(limit.rlim_cur, limit.rlim_max) >> 20;
109 qDebug(
"Kwave::MemoryManager: RLIMIT_DATA: %llu MB", physical_ulimit);
111 if (physical_ulimit < total) total = physical_ulimit;
116 if (getrlimit(RLIMIT_AS, &limit) == 0) {
117 quint64 total_ulimit =
118 qMin(limit.rlim_cur, limit.rlim_max) >> 20;
120 qDebug(
"Kwave::MemoryManager: RLIMIT_AS: %llu MB", total_ulimit);
122 if (total_ulimit < total) total = total_ulimit;
129 total = qMin(total, static_cast<quint64>(INT_MAX));
132 qDebug(
"Kwave::MemoryManager: => using up to %llu MB RAM", total);
153 QMutexLocker lock(&
m_lock);
173 QMutexLocker lock(&
m_lock);
186 QMutexLocker lock(&
m_lock);
201 QMutexLocker lock(&
m_lock);
208 QMutexLocker lock(&
m_lock);
230 for (
unsigned int i = 0; i < INT_MAX; i++) {
261 QList<Kwave::Handle> handles =
m_physical.keys();
262 QMutableListIterator<Kwave::Handle> it(handles);
264 while (it.hasPrevious()) {
272 qDebug(
"Kwave::MemoryManager[%9d] - swapping %2u MB out to make "\
273 "space for %2u MB", handle,
280 if (freed >= size)
return true;
293 QMutexLocker lock(&
m_lock);
311 qWarning(
"Kwave::MemoryManager::allocate(%u) - out of memory!",
327 quint64 available = (used < limit) ? (limit - used) : 0;
328 if ((size >> 20) >= available)
return 0;
332 if (!handle)
return 0;
335 void *mem = ::malloc(size);
346 m_stats.physical.handles++;
347 m_stats.physical.allocs++;
348 m_stats.physical.bytes += size;
359 used += (mem.
m_size >> 10) + 1;
369 used += (swapfile->
size() >> 10) + 1;
372 used += (swapfile->
size() >> 10) + 1;
375 used += (swapfile->
size() >> 10) + 1;
387 filename =
_(
"kwave-swapfile-%1-XXXXXX");
388 filename = filename.arg(static_cast<unsigned int>(handle),
389 10, 10, QLatin1Char(
'0'));
392 return file.absoluteFilePath();
403 quint64 limit = INT_MAX;
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)",
411 dump(
"allocateVirtual");
417 if (!handle)
return 0;
428 m_stats.swap.unmapped.bytes += size;
429 m_stats.swap.unmapped.handles++;
430 m_stats.swap.allocs++;
434 qWarning(
"Kwave::MemoryManager::allocateVirtual(%u): OOM, "\
435 "(used: %lluMB) - failed resizing swap file",
450 if (!
m_physical.contains(handle))
return false;
461 if (!temp_handle)
return false;
472 m_stats.physical.handles--;
473 m_stats.physical.frees++;
474 m_stats.physical.bytes -= mem.
m_size;
484 dump(
"convertToVirtual");
493 if (!new_size)
return false;
500 if (!swap)
return false;
505 if (!temp_handle)
return false;
509 Q_ASSERT(mem.
m_size >= new_size);
512 if (new_size <= swap->size()) {
521 m_stats.swap.unmapped.bytes -= swap->
size();
522 m_stats.swap.unmapped.handles--;
523 m_stats.swap.frees++;
538 dump(
"convertToPhysical");
557 size_t size = swap->
size();
562 quint64 available = (used < limit) ? (limit - used) : 0;
565 if ((size >> 20) >= available) {
577 QMutexLocker lock(&
m_lock);
591 size_t current_size = phys_c.
m_size;
600 if (!physical_freed) {
603 qDebug(
"Kwave::MemoryManager[%9d] - resize(%uMB) " 608 qDebug(
"Kwave::MemoryManager[%9d] - resize(%uMB) " 617 void *old_block = phys.
m_data;
618 void *new_block = ::realloc(old_block, size);
625 m_stats.physical.bytes -= current_size;
626 m_stats.physical.bytes += size;
669 size_t old_size = swap->
size();
671 bool ok = swap->
resize(size);
672 if (!ok)
return false;
674 m_stats.swap.unmapped.bytes -= old_size;
675 m_stats.swap.unmapped.bytes += size;
686 if (!handle)
return 0;
687 QMutexLocker lock(&
m_lock);
698 return swapfile->
size();
704 return swapfile->
size();
710 return swapfile->
size();
720 QMutexLocker lock(&
m_lock);
729 m_stats.physical.handles--;
730 m_stats.physical.frees++;
731 m_stats.physical.bytes -=
m_physical[handle].m_size;
756 m_stats.swap.unmapped.handles--;
757 m_stats.swap.unmapped.bytes -= swap->
size();
758 m_stats.swap.frees++;
776 QMutexLocker lock(&
m_lock);
779 if (!handle)
return Q_NULLPTR;
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();
823 void *mapped = swap->
map();
825 qDebug(
"Kwave::MemoryManager[%9d] - mmap FAILED", handle);
831 mapped = swap->
map();
832 qDebug(
"Kwave::MemoryManager[%9d] - retry: %p", handle, mapped);
835 if (!mapped)
return Q_NULLPTR;
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();
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();
884 QMutexLocker lock(&
m_lock);
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();
942 void *buffer,
unsigned int length)
944 QMutexLocker lock(&
m_lock);
946 if (!handle)
return 0;
954 char *data =
reinterpret_cast<char *
>(
m_physical[handle].m_data);
955 MEMCPY(buffer, data + offset, length);
965 char *data =
reinterpret_cast<char *
>(swap->
address());
968 MEMCPY(buffer, data + offset, length);
977 char *data =
reinterpret_cast<char *
>(swap->
address());
980 MEMCPY(buffer, data + offset, length);
990 length = swap->
read(offset, buffer, length);
999 const void *buffer,
unsigned int length)
1001 QMutexLocker lock(&
m_lock);
1003 if (!handle)
return 0;
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);
1034 swap->
write(offset, buffer, length);
1048 qDebug(
"------- %s -------",
function);
1050 qDebug(
" P[%5u]: %5u", static_cast<unsigned int>(handle),
1056 qDebug(
" M[%5u]: %5u", static_cast<unsigned int>(handle),
1063 qDebug(
" C[%5u]: %5u", static_cast<unsigned int>(handle),
1070 qDebug(
" U[%5u]: %5u", static_cast<unsigned int>(handle),
1074 qDebug(
"physical: %5llu MB, virtual: %5llu MB [m:%5u, c:%5u, u:%5u]",
1075 p_used, v_used, m, c, u);
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,
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(
"-----------------------------------------------------------------");
QHash< Kwave::Handle, Kwave::SwapFile * > m_unmapped_swap
static Kwave::MemoryManager g_instance
void setVirtualLimit(quint64 mb) Q_DECL_EXPORT
quint64 totalPhysical() Q_DECL_EXPORT
int readFrom(Kwave::Handle handle, unsigned int offset, void *buffer, unsigned int length) Q_DECL_EXPORT
bool convertToVirtual(Kwave::Handle handle, size_t new_size)
bool resize(Kwave::Handle handle, size_t size) Q_DECL_EXPORT
size_t sizeOf(Kwave::Handle handle) Q_DECL_EXPORT
static MemoryManager & instance() Q_DECL_EXPORT
int write(unsigned int offset, const void *buffer, unsigned int length)
Kwave::Handle newHandle()
bool convertToPhysical(Kwave::Handle handle, size_t new_size)
bool freePhysical(size_t size)
QHash< Kwave::Handle, Kwave::SwapFile * > m_mapped_swap
void setUndoLimit(quint64 mb) Q_DECL_EXPORT
void tryToMakePhysical(Kwave::Handle handle)
void free(Kwave::Handle &handle) Q_DECL_EXPORT
void unmapFromCache(Kwave::Handle handle)
int read(unsigned int offset, void *buffer, unsigned int length)
bool allocate(size_t size)
void setSwapDirectory(const QString &dir) Q_DECL_EXPORT
QHash< Kwave::Handle, Kwave::SwapFile * > m_cached_swap
void setPhysicalLimit(quint64 mb) Q_DECL_EXPORT
QString nextSwapFileName(Kwave::Handle handle)
Kwave::Handle allocatePhysical(size_t size)
quint64 undoLimit() const Q_DECL_EXPORT
static Kwave::Handle m_last_handle
void unmap(Kwave::Handle handle) Q_DECL_EXPORT
Kwave::Handle allocateVirtual(size_t size)
void * map(Kwave::Handle handle) Q_DECL_EXPORT
int writeTo(Kwave::Handle handle, unsigned int offset, const void *buffer, unsigned int length) Q_DECL_EXPORT
Kwave::Handle allocate(size_t size) Q_DECL_EXPORT
Kwave::LRU_Cache< Kwave::Handle, physical_memory_t > m_physical
void dump(const char *function)