23 #include <glog/logging.h>
40 #ifndef MAP_HUGE_SHIFT
41 #define MAP_HUGE_SHIFT 26
42 #endif // MAP_HUGE_SHIFT
44 #define MAP_HUGE_2MB (21 << MAP_HUGE_SHIFT)
45 #endif // MAP_HUGE_2MB
47 #define MAP_HUGE_1GB (30 << MAP_HUGE_SHIFT)
48 #endif // MAP_HUGE_1GB
53 AllocType alloc_type,
int numa_node) noexcept
54 : size_(0), alignment_(0), alloc_type_(kPosixMemalign), numa_node_(0),
56 alloc(size, alignment, alloc_type, numa_node);
70 if (alignment >= (1ULL << 30)) {
76 }
else if (alignment >= (1ULL << 21)) {
81 bool running_on_valgrind = RUNNING_ON_VALGRIND;
82 if (running_on_valgrind) {
87 char* ret =
reinterpret_cast<char*
>(::mmap(
90 PROT_READ | PROT_WRITE,
91 MAP_ANONYMOUS | MAP_PRIVATE | pagesize,
100 if (ret ==
nullptr || ret == MAP_FAILED) {
102 <<
". This error usually means you don't have enough hugepages allocated."
103 <<
" eg) sudo sh -c 'echo 196608 > /proc/sys/vm/nr_hugepages'";
117 int numa_node) noexcept {
121 alignment_ = alignment;
122 alloc_type_ = alloc_type;
123 numa_node_ = numa_node;
124 ASSERT_ND((alignment & (alignment - 1)) == 0);
125 if (alloc_type_ == kNumaMmapOneGbPages) {
126 alignment = 1ULL << 30;
128 if (size_ == 0 || size_ % alignment != 0) {
129 size_ = ((size_ / alignment) + 1) * alignment;
135 int original_node = 0;
142 int posix_memalign_ret;
143 switch (alloc_type_) {
147 posix_memalign_ret = ::posix_memalign(&block_, alignment, size_);
148 if (posix_memalign_ret != 0) {
152 case kNumaAllocInterleaved:
153 case kNumaAllocOnnode:
156 case kNumaMmapOneGbPages:
164 if (block_ ==
nullptr) {
165 LOG(ERROR) <<
"Aligned memory allocation failed. OS error=" <<
assorted::os_error() << *
this;
174 std::memset(block_, 0, size_);
179 LOG(INFO) <<
"Allocated memory in " << watch.
elapsed_ns() <<
"+"
180 << watch2.
elapsed_ns() <<
" ns (alloc+memset)." << *
this;
183 uint64_t required_size,
184 double expand_margin,
185 bool retain_content) noexcept {
187 LOG(FATAL) <<
"Misuse of assure_capacity. Can't extend a null buffer";
190 if (size_ >= required_size) {
193 if (expand_margin < 1) {
196 uint64_t expanded = required_size * expand_margin;
197 VLOG(0) <<
"Expanding work memory from " << size_ <<
" to " << expanded;
204 alloc(expanded, alignment_, alloc_type_, numa_node_);
206 LOG(ERROR) <<
"Out of memory error while expanding work memory from "
207 << size_ <<
" to " << expanded;
208 *
this = std::move(old);
213 if (retain_content) {
215 std::memcpy(block_, old.block_, old.size_);
223 *
this = std::move(other);
228 alignment_ = other.alignment_;
229 alloc_type_ = other.alloc_type_;
230 block_ = other.block_;
231 other.block_ =
nullptr;
236 if (block_ !=
nullptr) {
237 switch (alloc_type_) {
244 ::munmap(block_, size_);
254 o <<
"<AlignedMemory>";
255 o <<
"<is_null>" << v.
is_null() <<
"</is_null>";
256 o <<
"<size>" << v.
get_size() <<
"</size>";
261 o <<
"kPosixMemalign";
264 o <<
"kNumaAllocInterleaved";
267 o <<
"kNumaAllocOnnode";
270 o <<
"kNumaMmapOneGbPages";
275 o <<
")</alloc_type>";
276 o <<
"<numa_node>" <<
static_cast<int>(v.
get_numa_node()) <<
"</numa_node>";
277 o <<
"<address>" << v.
get_block() <<
"</address>";
278 o <<
"</AlignedMemory>";
283 o <<
"<AlignedMemorySlice>";
284 o <<
"<offset>" << v.
offset_ <<
"</offset>";
285 o <<
"<count>" << v.
count_ <<
"</count>";
289 o <<
"</AlignedMemorySlice>";
298 std::ifstream file(
"/proc/meminfo");
299 if (!file.is_open()) {
304 while (std::getline(file, line)) {
305 if (line.find(
"Hugepagesize:") != std::string::npos) {
310 if (line.find(
"1048576 kB") != std::string::npos) {
0x0001 : "GENERAL: Out of memory" .
0x0002 : "GENERAL: Invalid parameter given" .
numa_alloc_onnode() and numa_free().
uint64_t get_alignment() const
Returns the alignment of the memory block.
uint64_t count_
Byte count of this slice in memory_.
void release_block()
Releases the memory block.
Root package of FOEDUS (Fast Optimistic Engine for Data Unification Services).
AlignedMemory & operator=(const AlignedMemory &other)=delete
AlignedMemory * memory_
The wrapped memory.
AllocType
Type of new/delete operation for the block.
ErrorCode assure_capacity(uint64_t required_size, double expand_margin=2.0, bool retain_content=false) noexcept
If the current size is smaller than the given size, automatically expands.
void alloc(uint64_t size, uint64_t alignment, AllocType alloc_type, int numa_node) noexcept
Allocate a memory, releasing the current memory if exists.
void * alloc_mmap_1gb_pages(uint64_t size)
AllocType get_alloc_type() const
Returns type of new/delete operation for the block.
uint64_t stop()
Take another current time tick.
A slice of foedus::memory::AlignedMemory.
std::ostream & operator<<(std::ostream &o, const AlignedMemory &v)
void * get_block() const
Returns the memory block.
uint64_t get_size() const
Returns the byte size of the memory block.
std::string os_error()
Thread-safe strerror(errno).
uint64_t offset_
Byte offset of this slice in memory_.
Represents one memory block aligned to actual OS/hardware pages.
int mod_numa_node(int numa_node)
In order to run even on a non-numa machine or a machine with fewer sockets, we allow specifying arbit...
posix_memalign() and free().
char * alloc_mmap(uint64_t size, uint64_t alignment)
void numa_set_preferred(int node)
#define ASSERT_ND(x)
A warning-free wrapper macro of assert() that has no performance effect in release mode even when 'x'...
numa_alloc_interleaved() and numa_free().
A high-resolution stop watch.
bool is_1gb_hugepage_enabled()
Returns if 1GB hugepages were enabled.
ErrorCode
Enum of error codes defined in error_code.xmacro.
int get_numa_node() const
If alloc_type_ is kNumaAllocOnnode, returns the NUMA node this memory was allocated at...
AlignedMemory() noexcept
Empty constructor which allocates nothing.
uint64_t elapsed_ns() const
bool is_null() const
Returns if this object doesn't hold a valid memory block.