blob: 32c68ce4cd0db3baa73c5ff984cd637d54c3d30c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef DBCOMMON_SRC_DBCOMMON_UTILS_MEMORY_POOL_H_
#define DBCOMMON_SRC_DBCOMMON_UTILS_MEMORY_POOL_H_
#include <execinfo.h>
#include <unistd.h>
#include <cassert>
#include <limits>
#include <mutex> // NOLINT
#include <string>
#include <unordered_map>
#include "dbcommon/utils/cutils.h"
namespace dbcommon {
typedef struct MemAddr {
void *memPtr; // allocated raw memory ptr
size_t size;
} MemAddr;
// aligned memory ptr
typedef std::unordered_map<void *, MemAddr> MemAddrMap;
class MemoryPool {
public:
MemoryPool() {
freeMem.clear();
activeMem.clear();
}
~MemoryPool() { reset(); }
void reset() {
// for limit, activeMem is not empty when memory pool destruct
for (auto iter = activeMem.begin(); iter != activeMem.end(); ++iter) {
dbcommon::cnfree(iter->second.memPtr);
}
for (auto iter = freeMem.begin(); iter != freeMem.end(); ++iter) {
dbcommon::cnfree(iter->second.memPtr);
}
freeMem.clear();
activeMem.clear();
space = 0;
}
size_t getSpace() { return space; }
template <typename T>
T *malloc(size_t size) {
size_t newSize = kBlockSize;
while (newSize < size) newSize *= 2;
size_t align = alignof(T);
if (newSize - size < align) newSize += align;
void *p = nullptr;
size_t pSize = kMaxSize;
for (auto iter = freeMem.begin(); iter != freeMem.end(); ++iter) {
if (iter->second.size >= newSize && iter->second.size < pSize) {
p = iter->first;
pSize = iter->second.size;
}
}
if (p == nullptr) {
p = dbcommon::cnmalloc(newSize);
} else {
freeMem.erase(p);
newSize = pSize;
}
space = newSize;
void *ret = p;
activeMem[ret] = MemAddr{p, space};
return reinterpret_cast<T *>(ret);
}
template <typename T>
T *realloc(void *p, size_t size) {
auto iter = activeMem.find(p);
if (iter->second.size >= size) {
space = iter->second.size;
return reinterpret_cast<T *>(p);
}
size_t newSize = kBlockSize;
while (newSize < size) newSize *= 2;
size_t align = alignof(T);
if (newSize - size < align) newSize += align;
void *ret = dbcommon::cnrealloc(p, newSize);
space = newSize;
if (ret == p) {
activeMem[ret].size = space;
} else {
activeMem.erase(p);
p = ret;
ret = p;
activeMem[ret] = MemAddr{p, space};
}
return reinterpret_cast<T *>(ret);
}
void free(void *p) {
auto iter = activeMem.find(p);
freeMem.insert(*iter);
activeMem.erase(iter);
}
public:
std::string debugStr() {
std::string str;
str += "freeMemNum|activeMemNum(" + std::to_string(freeMem.size()) + "|" +
std::to_string(activeMem.size()) + "):";
for (auto iter = freeMem.begin(); iter != freeMem.end(); ++iter) {
std::stringstream strm;
strm << iter->second.memPtr;
str += strm.str() + "-" + std::to_string(iter->second.size) + ";";
}
str += "****";
for (auto iter = activeMem.begin(); iter != activeMem.end(); ++iter) {
std::stringstream strm;
strm << iter->second.memPtr;
str += strm.str() + "-" + std::to_string(iter->second.size) + ";";
}
return str;
}
std::string callstackStr() {
std::string str;
int nptrs;
void *buffer[1000];
char **strings;
nptrs = backtrace(buffer, 1000);
strings = backtrace_symbols(buffer, nptrs);
str += "\n";
for (int i = 0; i < nptrs; i++) {
str += strings[i];
str += "\n";
}
return str;
}
private:
const uint64_t kBlockSize = 1024;
const uint64_t kMaxSize = std::numeric_limits<uint64_t>::max();
MemAddrMap freeMem;
MemAddrMap activeMem;
size_t space = 0;
};
MemoryPool *getDefaultPool();
class ConcurrentMemoryPool : private MemoryPool {
public:
void reset() {
std::lock_guard<std::mutex> lockGuard(lock_);
MemoryPool::reset();
}
size_t getSpace() {
std::lock_guard<std::mutex> lockGuard(lock_);
return MemoryPool::getSpace();
}
template <typename T>
T *malloc(size_t size) {
std::lock_guard<std::mutex> lockGuard(lock_);
return MemoryPool::malloc<T>(size);
}
template <typename T>
T *realloc(void *p, size_t size) {
std::lock_guard<std::mutex> lockGuard(lock_);
return MemoryPool::realloc<T>(p, size);
}
void free(void *p) {
std::lock_guard<std::mutex> lockGuard(lock_);
return MemoryPool::free(p);
}
private:
std::mutex lock_;
};
} // namespace dbcommon
#endif // DBCOMMON_SRC_DBCOMMON_UTILS_MEMORY_POOL_H_