168 lines
5.3 KiB
C++
168 lines
5.3 KiB
C++
/*
|
|
* This file is open source software, licensed to you under the terms
|
|
* of the Apache License, Version 2.0 (the "License"). See the NOTICE file
|
|
* distributed with this work for additional information regarding copyright
|
|
* ownership. 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.
|
|
*/
|
|
/*
|
|
* Copyright (C) 2014 Cloudius Systems, Ltd.
|
|
*/
|
|
|
|
#ifndef MEMORY_HH_
|
|
#define MEMORY_HH_
|
|
|
|
#include "resource.hh"
|
|
#include <new>
|
|
#include <functional>
|
|
#include <vector>
|
|
|
|
|
|
/// \defgroup memory-module Memory management
|
|
///
|
|
/// Functions and classes for managing memory.
|
|
///
|
|
/// Memory management in seastar consists of the following:
|
|
///
|
|
/// - Low-level memory management in the \ref memory namespace.
|
|
/// - Various smart pointers: \ref shared_ptr, \ref lw_shared_ptr,
|
|
/// and \ref foreign_ptr.
|
|
/// - zero-copy support: \ref temporary_buffer and \ref deleter.
|
|
|
|
/// Low-level memory management support
|
|
///
|
|
/// The \c memory namespace provides functions and classes for interfacing
|
|
/// with the seastar memory allocator.
|
|
///
|
|
/// The seastar memory allocator splits system memory into a pool per
|
|
/// logical core (lcore). Memory allocated one an lcore should be freed
|
|
/// on the same lcore; failing to do so carries a severe performance
|
|
/// penalty. It is possible to share memory with another core, but this
|
|
/// should be limited to avoid cache coherency traffic.
|
|
namespace memory {
|
|
|
|
/// \cond internal
|
|
// TODO: Use getpagesize() in order to learn a size of a system PAGE.
|
|
static constexpr size_t page_bits = 12;
|
|
static constexpr size_t page_size = 1 << page_bits; // 4K
|
|
static constexpr size_t huge_page_size = 512 * page_size; // 2M
|
|
|
|
void configure(std::vector<resource::memory> m,
|
|
std::experimental::optional<std::string> hugetlbfs_path = {});
|
|
|
|
void* allocate_reclaimable(size_t size);
|
|
|
|
class reclaimer {
|
|
std::function<void ()> _reclaim;
|
|
public:
|
|
reclaimer(std::function<void ()> reclaim);
|
|
~reclaimer();
|
|
void do_reclaim() { _reclaim(); }
|
|
};
|
|
|
|
// Call periodically to recycle objects that were freed
|
|
// on cpu other than the one they were allocated on.
|
|
//
|
|
// Returns @true if any work was actually performed.
|
|
bool drain_cross_cpu_freelist();
|
|
|
|
|
|
// We don't want the memory code calling back into the rest of
|
|
// the system, so allow the rest of the system to tell the memory
|
|
// code how to initiate reclaim.
|
|
//
|
|
// When memory is low, calling \c hook(fn) will result in fn being called
|
|
// in a safe place wrt. allocations.
|
|
void set_reclaim_hook(
|
|
std::function<void (std::function<void ()>)> hook);
|
|
|
|
using physical_address = uint64_t;
|
|
|
|
struct translation {
|
|
translation() = default;
|
|
translation(physical_address a, size_t s) : addr(a), size(s) {}
|
|
physical_address addr = 0;
|
|
size_t size = 0;
|
|
};
|
|
|
|
// Translate a virtual address range to a physical range.
|
|
//
|
|
// Can return a smaller range (in which case the reminder needs
|
|
// to be translated again), or a zero sized range in case the
|
|
// translation is not known.
|
|
translation translate(const void* addr, size_t size);
|
|
|
|
/// \endcond
|
|
|
|
class statistics;
|
|
|
|
/// Capture a snapshot of memory allocation statistics for this lcore.
|
|
statistics stats();
|
|
|
|
/// Memory allocation statistics.
|
|
class statistics {
|
|
uint64_t _mallocs;
|
|
uint64_t _frees;
|
|
uint64_t _cross_cpu_frees;
|
|
private:
|
|
statistics(uint64_t mallocs, uint64_t frees, uint64_t cross_cpu_frees)
|
|
: _mallocs(mallocs), _frees(frees), _cross_cpu_frees(cross_cpu_frees) {}
|
|
public:
|
|
/// Total number of memory allocations calls since the system was started.
|
|
uint64_t mallocs() const { return _mallocs; }
|
|
/// Total number of memory deallocations calls since the system was started.
|
|
uint64_t frees() const { return _frees; }
|
|
/// Total number of memory deallocations that occured on a different lcore
|
|
/// than the one on which they were allocated.
|
|
uint64_t cross_cpu_frees() const { return _cross_cpu_frees; }
|
|
/// Total number of objects which were allocated but not freed.
|
|
size_t live_objects() const { return mallocs() - frees(); }
|
|
friend statistics stats();
|
|
};
|
|
|
|
|
|
}
|
|
|
|
class with_alignment {
|
|
size_t _align;
|
|
public:
|
|
with_alignment(size_t align) : _align(align) {}
|
|
size_t alignment() const { return _align; }
|
|
};
|
|
|
|
void* operator new(size_t size, with_alignment wa);
|
|
void* operator new[](size_t size, with_alignment wa);
|
|
void operator delete(void* ptr, with_alignment wa);
|
|
void operator delete[](void* ptr, with_alignment wa);
|
|
|
|
template <typename T, size_t Align>
|
|
class aligned_allocator {
|
|
public:
|
|
using value_type = T;
|
|
T* allocate(size_t n) const {
|
|
// FIXME: multiply can overflow?
|
|
return reinterpret_cast<T*>(::operator new(n * sizeof(T), with_alignment(Align)));
|
|
}
|
|
void deallocate(T* ptr) const {
|
|
return ::operator delete(ptr, with_alignment(Align));
|
|
}
|
|
bool operator==(const aligned_allocator& x) const {
|
|
return true;
|
|
}
|
|
bool operator!=(const aligned_allocator& x) const {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
#endif /* MEMORY_HH_ */
|